5 // Jb Evain (jbevain@gmail.com)
7 // Copyright (c) 2008 - 2011 Jb Evain
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.
30 using System
.Collections
.Generic
;
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
)
49 if (!self
.HasNestedTypes
)
52 foreach (var type
in self
.NestedTypes
.SelectMany (t
=> t
.GetAllTypes ()))
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
)
74 throw new ArgumentNullException ("self");
76 foreach (var instruction
in self
.Instructions
) {
77 if (instruction
.OpCode
.OpCodeType
!= OpCodeType
.Macro
)
80 switch (instruction
.OpCode
.Code
) {
82 ExpandMacro (instruction
, OpCodes
.Ldarg
, self
.GetParameter (0));
85 ExpandMacro (instruction
, OpCodes
.Ldarg
, self
.GetParameter (1));
88 ExpandMacro (instruction
, OpCodes
.Ldarg
, self
.GetParameter (2));
91 ExpandMacro (instruction
, OpCodes
.Ldarg
, self
.GetParameter (3));
94 ExpandMacro (instruction
, OpCodes
.Ldloc
, self
.Variables
[0]);
97 ExpandMacro (instruction
, OpCodes
.Ldloc
, self
.Variables
[1]);
100 ExpandMacro (instruction
, OpCodes
.Ldloc
, self
.Variables
[2]);
103 ExpandMacro (instruction
, OpCodes
.Ldloc
, self
.Variables
[3]);
106 ExpandMacro (instruction
, OpCodes
.Stloc
, self
.Variables
[0]);
109 ExpandMacro (instruction
, OpCodes
.Stloc
, self
.Variables
[1]);
112 ExpandMacro (instruction
, OpCodes
.Stloc
, self
.Variables
[2]);
115 ExpandMacro (instruction
, OpCodes
.Stloc
, self
.Variables
[3]);
118 instruction
.OpCode
= OpCodes
.Ldarg
;
121 instruction
.OpCode
= OpCodes
.Ldarga
;
124 instruction
.OpCode
= OpCodes
.Starg
;
127 instruction
.OpCode
= OpCodes
.Ldloc
;
130 instruction
.OpCode
= OpCodes
.Ldloca
;
133 instruction
.OpCode
= OpCodes
.Stloc
;
136 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, -1);
139 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, 0);
142 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, 1);
145 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, 2);
148 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, 3);
151 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, 4);
154 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, 5);
157 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, 6);
160 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, 7);
163 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, 8);
166 ExpandMacro (instruction
, OpCodes
.Ldc_I4
, (int) (sbyte) instruction
.Operand
);
169 instruction
.OpCode
= OpCodes
.Br
;
172 instruction
.OpCode
= OpCodes
.Brfalse
;
175 instruction
.OpCode
= OpCodes
.Brtrue
;
178 instruction
.OpCode
= OpCodes
.Beq
;
181 instruction
.OpCode
= OpCodes
.Bge
;
184 instruction
.OpCode
= OpCodes
.Bgt
;
187 instruction
.OpCode
= OpCodes
.Ble
;
190 instruction
.OpCode
= OpCodes
.Blt
;
193 instruction
.OpCode
= OpCodes
.Bne_Un
;
196 instruction
.OpCode
= OpCodes
.Bge_Un
;
199 instruction
.OpCode
= OpCodes
.Bgt_Un
;
202 instruction
.OpCode
= OpCodes
.Ble_Un
;
205 instruction
.OpCode
= OpCodes
.Blt_Un
;
208 instruction
.OpCode
= OpCodes
.Leave
;
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
)
229 throw new ArgumentNullException ("self");
231 var method
= self
.Method
;
233 foreach (var instruction
in self
.Instructions
) {
235 switch (instruction
.OpCode
.Code
) {
237 index
= ((ParameterDefinition
) instruction
.Operand
).Index
;
238 if (index
== -1 && instruction
.Operand
== self
.ThisParameter
)
240 else if (method
.HasThis
)
245 MakeMacro (instruction
, OpCodes
.Ldarg_0
);
248 MakeMacro (instruction
, OpCodes
.Ldarg_1
);
251 MakeMacro (instruction
, OpCodes
.Ldarg_2
);
254 MakeMacro (instruction
, OpCodes
.Ldarg_3
);
258 ExpandMacro (instruction
, OpCodes
.Ldarg_S
, instruction
.Operand
);
263 index
= ((VariableDefinition
) instruction
.Operand
).Index
;
266 MakeMacro (instruction
, OpCodes
.Ldloc_0
);
269 MakeMacro (instruction
, OpCodes
.Ldloc_1
);
272 MakeMacro (instruction
, OpCodes
.Ldloc_2
);
275 MakeMacro (instruction
, OpCodes
.Ldloc_3
);
279 ExpandMacro (instruction
, OpCodes
.Ldloc_S
, instruction
.Operand
);
284 index
= ((VariableDefinition
) instruction
.Operand
).Index
;
287 MakeMacro (instruction
, OpCodes
.Stloc_0
);
290 MakeMacro (instruction
, OpCodes
.Stloc_1
);
293 MakeMacro (instruction
, OpCodes
.Stloc_2
);
296 MakeMacro (instruction
, OpCodes
.Stloc_3
);
300 ExpandMacro (instruction
, OpCodes
.Stloc_S
, instruction
.Operand
);
305 index
= ((ParameterDefinition
) instruction
.Operand
).Index
;
306 if (index
== -1 && instruction
.Operand
== self
.ThisParameter
)
308 else if (method
.HasThis
)
311 ExpandMacro (instruction
, OpCodes
.Ldarga_S
, instruction
.Operand
);
314 if (((VariableDefinition
) instruction
.Operand
).Index
< 256)
315 ExpandMacro (instruction
, OpCodes
.Ldloca_S
, instruction
.Operand
);
318 int i
= (int) instruction
.Operand
;
321 MakeMacro (instruction
, OpCodes
.Ldc_I4_M1
);
324 MakeMacro (instruction
, OpCodes
.Ldc_I4_0
);
327 MakeMacro (instruction
, OpCodes
.Ldc_I4_1
);
330 MakeMacro (instruction
, OpCodes
.Ldc_I4_2
);
333 MakeMacro (instruction
, OpCodes
.Ldc_I4_3
);
336 MakeMacro (instruction
, OpCodes
.Ldc_I4_4
);
339 MakeMacro (instruction
, OpCodes
.Ldc_I4_5
);
342 MakeMacro (instruction
, OpCodes
.Ldc_I4_6
);
345 MakeMacro (instruction
, OpCodes
.Ldc_I4_7
);
348 MakeMacro (instruction
, OpCodes
.Ldc_I4_8
);
351 if (i
>= -128 && i
< 128)
352 ExpandMacro (instruction
, OpCodes
.Ldc_I4_S
, (sbyte) i
);
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
)
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))
381 switch (instruction
.OpCode
.Code
) {
383 instruction
.OpCode
= OpCodes
.Br_S
;
386 instruction
.OpCode
= OpCodes
.Brfalse_S
;
389 instruction
.OpCode
= OpCodes
.Brtrue_S
;
392 instruction
.OpCode
= OpCodes
.Beq_S
;
395 instruction
.OpCode
= OpCodes
.Bge_S
;
398 instruction
.OpCode
= OpCodes
.Bgt_S
;
401 instruction
.OpCode
= OpCodes
.Ble_S
;
404 instruction
.OpCode
= OpCodes
.Blt_S
;
407 instruction
.OpCode
= OpCodes
.Bne_Un_S
;
410 instruction
.OpCode
= OpCodes
.Bge_Un_S
;
413 instruction
.OpCode
= OpCodes
.Bgt_Un_S
;
416 instruction
.OpCode
= OpCodes
.Ble_Un_S
;
419 instruction
.OpCode
= OpCodes
.Blt_Un_S
;
422 instruction
.OpCode
= OpCodes
.Leave_S
;
429 static void ComputeOffsets (MethodBody body
)
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
) {
444 return self
.ThisParameter
;
449 var parameters
= method
.Parameters
;
451 if (index
< 0 || index
>= parameters
.Count
)
454 return parameters
[index
];
457 public static bool Implements (this TypeReference self
, string interfaceName
)
459 if (interfaceName
== null)
460 throw new ArgumentNullException ("interfaceName");
464 TypeDefinition type
= self
.Resolve ();
466 return false; // not enough information available
468 // special case, check if we implement ourselves
469 if (type
.IsInterface
&& (type
.FullName
== interfaceName
))
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
)
484 //if not, then maybe one of its parent interfaces does
485 if (Implements (iface
.InterfaceType
.Resolve (), interfaceName
, generic
))
490 type
= type
.BaseType
!= null ? type
.BaseType
.Resolve () : null;
495 public static bool Inherits (this TypeReference self
, string @namespace, string name
)
497 if (@namespace == null)
498 throw new ArgumentNullException ("namespace");
500 throw new ArgumentNullException ("name");
504 TypeReference current
= self
.Resolve ();
505 while (current
!= null) {
506 if (current
.Is (@namespace, name
))
508 if (current
.Is ("System", "Object"))
511 TypeDefinition td
= current
.Resolve ();
513 return false; // could not resolve type
514 current
= td
.BaseType
;