[tuner/linker] Update code to fix warnings after cecil update.
[mono-project.git] / mcs / tools / tuner / Mono.Tuner / CecilRocks.cs
blob69958598dda2c3386fb92a7adaadf4bc26f31da7
1 //
2 // MethodBodyRocks.cs
3 //
4 // Author:
5 // Jb Evain (jbevain@gmail.com)
6 //
7 // Copyright (c) 2008 - 2011 Jb Evain
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 using System;
30 using System.Collections.Generic;
31 using System.Linq;
33 using Mono.Cecil;
34 using Mono.Cecil.Cil;
36 namespace Mono.Tuner {
38 public static class MethodBodyRocks {
40 public static IEnumerable<TypeDefinition> GetAllTypes (this ModuleDefinition self)
42 return self.Types.SelectMany (t => t.GetAllTypes ());
45 static IEnumerable<TypeDefinition> GetAllTypes (this TypeDefinition self)
47 yield return self;
49 if (!self.HasNestedTypes)
50 yield break;
52 foreach (var type in self.NestedTypes.SelectMany (t => t.GetAllTypes ()))
53 yield return type;
56 public static IEnumerable<MethodDefinition> GetMethods (this TypeDefinition self)
58 return self.Methods.Where (m => !m.IsConstructor);
61 public static IEnumerable<MethodDefinition> GetConstructors (this TypeDefinition self)
63 return self.Methods.Where (m => m.IsConstructor);
66 public static MethodDefinition GetTypeConstructor (this TypeDefinition self)
68 return self.GetConstructors ().FirstOrDefault (c => c.IsStatic);
71 public static void SimplifyMacros (this MethodBody self)
73 if (self == null)
74 throw new ArgumentNullException ("self");
76 foreach (var instruction in self.Instructions) {
77 if (instruction.OpCode.OpCodeType != OpCodeType.Macro)
78 continue;
80 switch (instruction.OpCode.Code) {
81 case Code.Ldarg_0:
82 ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (0));
83 break;
84 case Code.Ldarg_1:
85 ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (1));
86 break;
87 case Code.Ldarg_2:
88 ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (2));
89 break;
90 case Code.Ldarg_3:
91 ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (3));
92 break;
93 case Code.Ldloc_0:
94 ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [0]);
95 break;
96 case Code.Ldloc_1:
97 ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [1]);
98 break;
99 case Code.Ldloc_2:
100 ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [2]);
101 break;
102 case Code.Ldloc_3:
103 ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [3]);
104 break;
105 case Code.Stloc_0:
106 ExpandMacro (instruction, OpCodes.Stloc, self.Variables [0]);
107 break;
108 case Code.Stloc_1:
109 ExpandMacro (instruction, OpCodes.Stloc, self.Variables [1]);
110 break;
111 case Code.Stloc_2:
112 ExpandMacro (instruction, OpCodes.Stloc, self.Variables [2]);
113 break;
114 case Code.Stloc_3:
115 ExpandMacro (instruction, OpCodes.Stloc, self.Variables [3]);
116 break;
117 case Code.Ldarg_S:
118 instruction.OpCode = OpCodes.Ldarg;
119 break;
120 case Code.Ldarga_S:
121 instruction.OpCode = OpCodes.Ldarga;
122 break;
123 case Code.Starg_S:
124 instruction.OpCode = OpCodes.Starg;
125 break;
126 case Code.Ldloc_S:
127 instruction.OpCode = OpCodes.Ldloc;
128 break;
129 case Code.Ldloca_S:
130 instruction.OpCode = OpCodes.Ldloca;
131 break;
132 case Code.Stloc_S:
133 instruction.OpCode = OpCodes.Stloc;
134 break;
135 case Code.Ldc_I4_M1:
136 ExpandMacro (instruction, OpCodes.Ldc_I4, -1);
137 break;
138 case Code.Ldc_I4_0:
139 ExpandMacro (instruction, OpCodes.Ldc_I4, 0);
140 break;
141 case Code.Ldc_I4_1:
142 ExpandMacro (instruction, OpCodes.Ldc_I4, 1);
143 break;
144 case Code.Ldc_I4_2:
145 ExpandMacro (instruction, OpCodes.Ldc_I4, 2);
146 break;
147 case Code.Ldc_I4_3:
148 ExpandMacro (instruction, OpCodes.Ldc_I4, 3);
149 break;
150 case Code.Ldc_I4_4:
151 ExpandMacro (instruction, OpCodes.Ldc_I4, 4);
152 break;
153 case Code.Ldc_I4_5:
154 ExpandMacro (instruction, OpCodes.Ldc_I4, 5);
155 break;
156 case Code.Ldc_I4_6:
157 ExpandMacro (instruction, OpCodes.Ldc_I4, 6);
158 break;
159 case Code.Ldc_I4_7:
160 ExpandMacro (instruction, OpCodes.Ldc_I4, 7);
161 break;
162 case Code.Ldc_I4_8:
163 ExpandMacro (instruction, OpCodes.Ldc_I4, 8);
164 break;
165 case Code.Ldc_I4_S:
166 ExpandMacro (instruction, OpCodes.Ldc_I4, (int) (sbyte) instruction.Operand);
167 break;
168 case Code.Br_S:
169 instruction.OpCode = OpCodes.Br;
170 break;
171 case Code.Brfalse_S:
172 instruction.OpCode = OpCodes.Brfalse;
173 break;
174 case Code.Brtrue_S:
175 instruction.OpCode = OpCodes.Brtrue;
176 break;
177 case Code.Beq_S:
178 instruction.OpCode = OpCodes.Beq;
179 break;
180 case Code.Bge_S:
181 instruction.OpCode = OpCodes.Bge;
182 break;
183 case Code.Bgt_S:
184 instruction.OpCode = OpCodes.Bgt;
185 break;
186 case Code.Ble_S:
187 instruction.OpCode = OpCodes.Ble;
188 break;
189 case Code.Blt_S:
190 instruction.OpCode = OpCodes.Blt;
191 break;
192 case Code.Bne_Un_S:
193 instruction.OpCode = OpCodes.Bne_Un;
194 break;
195 case Code.Bge_Un_S:
196 instruction.OpCode = OpCodes.Bge_Un;
197 break;
198 case Code.Bgt_Un_S:
199 instruction.OpCode = OpCodes.Bgt_Un;
200 break;
201 case Code.Ble_Un_S:
202 instruction.OpCode = OpCodes.Ble_Un;
203 break;
204 case Code.Blt_Un_S:
205 instruction.OpCode = OpCodes.Blt_Un;
206 break;
207 case Code.Leave_S:
208 instruction.OpCode = OpCodes.Leave;
209 break;
214 static void ExpandMacro (Instruction instruction, OpCode opcode, object operand)
216 instruction.OpCode = opcode;
217 instruction.Operand = operand;
220 static void MakeMacro (Instruction instruction, OpCode opcode)
222 instruction.OpCode = opcode;
223 instruction.Operand = null;
226 public static void OptimizeMacros (this MethodBody self)
228 if (self == null)
229 throw new ArgumentNullException ("self");
231 var method = self.Method;
233 foreach (var instruction in self.Instructions) {
234 int index;
235 switch (instruction.OpCode.Code) {
236 case Code.Ldarg:
237 index = ((ParameterDefinition) instruction.Operand).Index;
238 if (index == -1 && instruction.Operand == self.ThisParameter)
239 index = 0;
240 else if (method.HasThis)
241 index++;
243 switch (index) {
244 case 0:
245 MakeMacro (instruction, OpCodes.Ldarg_0);
246 break;
247 case 1:
248 MakeMacro (instruction, OpCodes.Ldarg_1);
249 break;
250 case 2:
251 MakeMacro (instruction, OpCodes.Ldarg_2);
252 break;
253 case 3:
254 MakeMacro (instruction, OpCodes.Ldarg_3);
255 break;
256 default:
257 if (index < 256)
258 ExpandMacro (instruction, OpCodes.Ldarg_S, instruction.Operand);
259 break;
261 break;
262 case Code.Ldloc:
263 index = ((VariableDefinition) instruction.Operand).Index;
264 switch (index) {
265 case 0:
266 MakeMacro (instruction, OpCodes.Ldloc_0);
267 break;
268 case 1:
269 MakeMacro (instruction, OpCodes.Ldloc_1);
270 break;
271 case 2:
272 MakeMacro (instruction, OpCodes.Ldloc_2);
273 break;
274 case 3:
275 MakeMacro (instruction, OpCodes.Ldloc_3);
276 break;
277 default:
278 if (index < 256)
279 ExpandMacro (instruction, OpCodes.Ldloc_S, instruction.Operand);
280 break;
282 break;
283 case Code.Stloc:
284 index = ((VariableDefinition) instruction.Operand).Index;
285 switch (index) {
286 case 0:
287 MakeMacro (instruction, OpCodes.Stloc_0);
288 break;
289 case 1:
290 MakeMacro (instruction, OpCodes.Stloc_1);
291 break;
292 case 2:
293 MakeMacro (instruction, OpCodes.Stloc_2);
294 break;
295 case 3:
296 MakeMacro (instruction, OpCodes.Stloc_3);
297 break;
298 default:
299 if (index < 256)
300 ExpandMacro (instruction, OpCodes.Stloc_S, instruction.Operand);
301 break;
303 break;
304 case Code.Ldarga:
305 index = ((ParameterDefinition) instruction.Operand).Index;
306 if (index == -1 && instruction.Operand == self.ThisParameter)
307 index = 0;
308 else if (method.HasThis)
309 index++;
310 if (index < 256)
311 ExpandMacro (instruction, OpCodes.Ldarga_S, instruction.Operand);
312 break;
313 case Code.Ldloca:
314 if (((VariableDefinition) instruction.Operand).Index < 256)
315 ExpandMacro (instruction, OpCodes.Ldloca_S, instruction.Operand);
316 break;
317 case Code.Ldc_I4:
318 int i = (int) instruction.Operand;
319 switch (i) {
320 case -1:
321 MakeMacro (instruction, OpCodes.Ldc_I4_M1);
322 break;
323 case 0:
324 MakeMacro (instruction, OpCodes.Ldc_I4_0);
325 break;
326 case 1:
327 MakeMacro (instruction, OpCodes.Ldc_I4_1);
328 break;
329 case 2:
330 MakeMacro (instruction, OpCodes.Ldc_I4_2);
331 break;
332 case 3:
333 MakeMacro (instruction, OpCodes.Ldc_I4_3);
334 break;
335 case 4:
336 MakeMacro (instruction, OpCodes.Ldc_I4_4);
337 break;
338 case 5:
339 MakeMacro (instruction, OpCodes.Ldc_I4_5);
340 break;
341 case 6:
342 MakeMacro (instruction, OpCodes.Ldc_I4_6);
343 break;
344 case 7:
345 MakeMacro (instruction, OpCodes.Ldc_I4_7);
346 break;
347 case 8:
348 MakeMacro (instruction, OpCodes.Ldc_I4_8);
349 break;
350 default:
351 if (i >= -128 && i < 128)
352 ExpandMacro (instruction, OpCodes.Ldc_I4_S, (sbyte) i);
353 break;
355 break;
359 OptimizeBranches (self);
362 static void OptimizeBranches (MethodBody body)
364 ComputeOffsets (body);
366 foreach (var instruction in body.Instructions) {
367 if (instruction.OpCode.OperandType != OperandType.InlineBrTarget)
368 continue;
370 if (OptimizeBranch (instruction))
371 ComputeOffsets (body);
375 static bool OptimizeBranch (Instruction instruction)
377 var offset = ((Instruction) instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4);
378 if (!(offset >= -128 && offset <= 127))
379 return false;
381 switch (instruction.OpCode.Code) {
382 case Code.Br:
383 instruction.OpCode = OpCodes.Br_S;
384 break;
385 case Code.Brfalse:
386 instruction.OpCode = OpCodes.Brfalse_S;
387 break;
388 case Code.Brtrue:
389 instruction.OpCode = OpCodes.Brtrue_S;
390 break;
391 case Code.Beq:
392 instruction.OpCode = OpCodes.Beq_S;
393 break;
394 case Code.Bge:
395 instruction.OpCode = OpCodes.Bge_S;
396 break;
397 case Code.Bgt:
398 instruction.OpCode = OpCodes.Bgt_S;
399 break;
400 case Code.Ble:
401 instruction.OpCode = OpCodes.Ble_S;
402 break;
403 case Code.Blt:
404 instruction.OpCode = OpCodes.Blt_S;
405 break;
406 case Code.Bne_Un:
407 instruction.OpCode = OpCodes.Bne_Un_S;
408 break;
409 case Code.Bge_Un:
410 instruction.OpCode = OpCodes.Bge_Un_S;
411 break;
412 case Code.Bgt_Un:
413 instruction.OpCode = OpCodes.Bgt_Un_S;
414 break;
415 case Code.Ble_Un:
416 instruction.OpCode = OpCodes.Ble_Un_S;
417 break;
418 case Code.Blt_Un:
419 instruction.OpCode = OpCodes.Blt_Un_S;
420 break;
421 case Code.Leave:
422 instruction.OpCode = OpCodes.Leave_S;
423 break;
426 return true;
429 static void ComputeOffsets (MethodBody body)
431 var offset = 0;
432 foreach (var instruction in body.Instructions) {
433 instruction.Offset = offset;
434 offset += instruction.GetSize ();
438 public static ParameterDefinition GetParameter (this MethodBody self, int index)
440 var method = self.Method;
442 if (method.HasThis) {
443 if (index == 0)
444 return self.ThisParameter;
446 index--;
449 var parameters = method.Parameters;
451 if (index < 0 || index >= parameters.Count)
452 return null;
454 return parameters [index];
457 public static bool Implements (this TypeReference self, string interfaceName)
459 if (interfaceName == null)
460 throw new ArgumentNullException ("interfaceName");
461 if (self == null)
462 return false;
464 TypeDefinition type = self.Resolve ();
465 if (type == null)
466 return false; // not enough information available
468 // special case, check if we implement ourselves
469 if (type.IsInterface && (type.FullName == interfaceName))
470 return true;
472 return Implements (type, interfaceName, (interfaceName.IndexOf ('`') >= 0));
475 public static bool Implements (TypeDefinition type, string interfaceName, bool generic)
477 while (type != null) {
478 // does the type implements it itself
479 if (type.HasInterfaces) {
480 foreach (var iface in type.Interfaces) {
481 string fullname = (generic) ? iface.InterfaceType.GetElementType ().FullName : iface.InterfaceType.FullName;
482 if (fullname == interfaceName)
483 return true;
484 //if not, then maybe one of its parent interfaces does
485 if (Implements (iface.InterfaceType.Resolve (), interfaceName, generic))
486 return true;
490 type = type.BaseType != null ? type.BaseType.Resolve () : null;
492 return false;
495 public static bool Inherits (this TypeReference self, string @namespace, string name)
497 if (@namespace == null)
498 throw new ArgumentNullException ("namespace");
499 if (name == null)
500 throw new ArgumentNullException ("name");
501 if (self == null)
502 return false;
504 TypeReference current = self.Resolve ();
505 while (current != null) {
506 if (current.Is (@namespace, name))
507 return true;
508 if (current.Is ("System", "Object"))
509 return false;
511 TypeDefinition td = current.Resolve ();
512 if (td == null)
513 return false; // could not resolve type
514 current = td.BaseType;
516 return false;