1 //
2 // BlockStartGatherer.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.DataStructures;
32 using Mono.CodeContracts.Static.Providers;
33 
34 namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders {
35 	class BlockStartGatherer<Label> : ILVisitorBase<Label, Dummy, Dummy, Dummy, bool>,
36 	                                           IAggregateVisitor<Label, Dummy, bool> {
37 		private readonly SubroutineBuilder<Label> parent;
38 
BlockStartGatherer(SubroutineBuilder<Label> parent)39 		public BlockStartGatherer (SubroutineBuilder<Label> parent)
40 		{
41 			this.parent = parent;
42 		}
43 
44 		#region IAggregateVisitor<Label,Dummy,bool> Members
Branch(Label pc, Label target, bool leavesExceptionBlock, Dummy data)45 		public override bool Branch (Label pc, Label target, bool leavesExceptionBlock, Dummy data)
46 		{
47 			AddTargetLabel (target);
48 			return true;
49 		}
50 
BranchCond(Label pc, Label target, BranchOperator bop, Dummy value1, Dummy value2, Dummy data)51 		public override bool BranchCond (Label pc, Label target, BranchOperator bop, Dummy value1, Dummy value2, Dummy data)
52 		{
53 			AddTargetLabel (target);
54 			return true;
55 		}
56 
BranchFalse(Label pc, Label target, Dummy cond, Dummy data)57 		public override bool BranchFalse (Label pc, Label target, Dummy cond, Dummy data)
58 		{
59 			AddTargetLabel (target);
60 			return true;
61 		}
62 
BranchTrue(Label pc, Label target, Dummy cond, Dummy data)63 		public override bool BranchTrue (Label pc, Label target, Dummy cond, Dummy data)
64 		{
65 			AddTargetLabel (target);
66 			return true;
67 		}
68 
EndFinally(Label pc, Dummy data)69 		public override bool EndFinally (Label pc, Dummy data)
70 		{
71 			return true;
72 		}
73 
Return(Label pc, Dummy source, Dummy data)74 		public override bool Return (Label pc, Dummy source, Dummy data)
75 		{
76 			return true;
77 		}
78 
Rethrow(Label pc, Dummy data)79 		public override bool Rethrow (Label pc, Dummy data)
80 		{
81 			return true;
82 		}
83 
Throw(Label pc, Dummy exception, Dummy data)84 		public override bool Throw (Label pc, Dummy exception, Dummy data)
85 		{
86 			return true;
87 		}
88 
Call(Label pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, Dummy data)89 		public override bool Call<TypeList, ArgList> (Label pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, Dummy data)
90 		{
91 			return CallHelper (pc, method, false, virt);
92 		}
93 
ConstrainedCallvirt(Label pc, Method method, TypeNode constraint, TypeList extraVarargs, Dummy dest, ArgList args, Dummy data)94 		public override bool ConstrainedCallvirt<TypeList, ArgList> (Label pc, Method method, TypeNode constraint, TypeList extraVarargs, Dummy dest, ArgList args, Dummy data)
95 		{
96 			return CallHelper (pc, method, false, true);
97 		}
98 
NewObj(Label pc, Method ctor, Dummy dest, ArgList args, Dummy data)99 		public override bool NewObj<ArgList> (Label pc, Method ctor, Dummy dest, ArgList args, Dummy data)
100 		{
101 			return CallHelper (pc, ctor, true, false);
102 		}
103 
BeginOld(Label pc, Label matchingEnd, Dummy data)104 		public override bool BeginOld (Label pc, Label matchingEnd, Dummy data)
105 		{
106 			AddTargetLabel (pc);
107 			this.parent.BeginOldHook (pc);
108 			return false;
109 		}
110 
EndOld(Label pc, Label matchingBegin, TypeNode type, Dummy dest, Dummy source, Dummy data)111 		public override bool EndOld (Label pc, Label matchingBegin, TypeNode type, Dummy dest, Dummy source, Dummy data)
112 		{
113 			this.parent.EndOldHook (pc);
114 			return true;
115 		}
116 
Aggregate(Label pc, Label aggregateStart, bool canBeTargetOfBranch, Dummy data)117 		public bool Aggregate (Label pc, Label aggregateStart, bool canBeTargetOfBranch, Dummy data)
118 		{
119 			return TraceAggregateSequentally (aggregateStart);
120 		}
121 		#endregion
122 
DefaultVisit(Label pc, Dummy data)123 		public override bool DefaultVisit (Label pc, Dummy data)
124 		{
125 			return false;
126 		}
127 
CallHelper(Label pc, Method method, bool isNewObj, bool isVirtual)128 		private bool CallHelper (Label pc, Method method, bool isNewObj, bool isVirtual)
129 		{
130 			AddBlockStart (pc);
131 			if (isNewObj)
132 				this.parent.AddNewObjSite (pc, method);
133 			else
134 				this.parent.AddMethodCallSite (pc, new Pair<Method, bool> (method, isVirtual));
135 
136 			return true;
137 		}
138 
TraceAggregateSequentally(Label current)139 		public bool TraceAggregateSequentally (Label current)
140 		{
141 			bool isCurrentBranches;
142 			bool isCurrentHasSuccessor;
143 			do {
144 				ICodeProvider<Label> codeProvider = this.parent.CodeProvider;
145 				isCurrentBranches = codeProvider.Decode<BlockStartGatherer<Label>, Dummy, bool> (current, this, Dummy.Value);
146 				isCurrentHasSuccessor = codeProvider.Next (current, out current);
147 				if (isCurrentBranches && isCurrentHasSuccessor)
148 					AddBlockStart (current);
149 			} while (isCurrentHasSuccessor);
150 
151 			return isCurrentBranches;
152 		}
153 
AddBlockStart(Label target)154 		private void AddBlockStart (Label target)
155 		{
156 			this.parent.AddBlockStart (target);
157 		}
158 
AddTargetLabel(Label target)159 		private void AddTargetLabel (Label target)
160 		{
161 			this.parent.AddTargetLabel (target);
162 		}
163 	}
164 }
165