PageRenderTime 1626ms CodeModel.GetById 624ms app.highlight 860ms RepoModel.GetById 61ms app.codeStats 0ms

/mcs/tools/tuner/Mono.Tuner/CecilRocks.cs

https://github.com/hollow87/mono
C# | 518 lines | 445 code | 43 blank | 30 comment | 71 complexity | 2215dd00e8ffba42e597aad594c19fb1 MD5 | raw file
  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:
 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
 29using System;
 30using System.Collections.Generic;
 31using System.Linq;
 32
 33using Mono.Cecil;
 34using Mono.Cecil.Cil;
 35
 36namespace Mono.Tuner {
 37
 38	public static class MethodBodyRocks {
 39
 40		public static IEnumerable<TypeDefinition> GetAllTypes (this ModuleDefinition self)
 41		{
 42			return self.Types.SelectMany (t => t.GetAllTypes ());
 43		}
 44
 45		static IEnumerable<TypeDefinition> GetAllTypes (this TypeDefinition self)
 46		{
 47			yield return self;
 48
 49			if (!self.HasNestedTypes)
 50				yield break;
 51
 52			foreach (var type in self.NestedTypes.SelectMany (t => t.GetAllTypes ()))
 53				yield return type;
 54		}
 55
 56		public static IEnumerable<MethodDefinition> GetMethods (this TypeDefinition self)
 57		{
 58			return self.Methods.Where (m => !m.IsConstructor);
 59		}
 60
 61		public static IEnumerable<MethodDefinition> GetConstructors (this TypeDefinition self)
 62		{
 63			return self.Methods.Where (m => m.IsConstructor);
 64		}
 65
 66		public static MethodDefinition GetTypeConstructor (this TypeDefinition self)
 67		{
 68			return self.GetConstructors ().FirstOrDefault (c => c.IsStatic);
 69		}
 70
 71		public static void SimplifyMacros (this MethodBody self)
 72		{
 73			if (self == null)
 74				throw new ArgumentNullException ("self");
 75
 76			foreach (var instruction in self.Instructions) {
 77				if (instruction.OpCode.OpCodeType != OpCodeType.Macro)
 78					continue;
 79
 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;
210				}
211			}
212		}
213
214		static void ExpandMacro (Instruction instruction, OpCode opcode, object operand)
215		{
216			instruction.OpCode = opcode;
217			instruction.Operand = operand;
218		}
219
220		static void MakeMacro (Instruction instruction, OpCode opcode)
221		{
222			instruction.OpCode = opcode;
223			instruction.Operand = null;
224		}
225
226		public static void OptimizeMacros (this MethodBody self)
227		{
228			if (self == null)
229				throw new ArgumentNullException ("self");
230
231			var method = self.Method;
232
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++;
242
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;
260					}
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;
281					}
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;
302					}
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;
354					}
355					break;
356				}
357			}
358
359			OptimizeBranches (self);
360		}
361
362		static void OptimizeBranches (MethodBody body)
363		{
364			ComputeOffsets (body);
365
366			foreach (var instruction in body.Instructions) {
367				if (instruction.OpCode.OperandType != OperandType.InlineBrTarget)
368					continue;
369
370				if (OptimizeBranch (instruction))
371					ComputeOffsets (body);
372			}
373		}
374
375		static bool OptimizeBranch (Instruction instruction)
376		{
377			var offset = ((Instruction) instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4);
378			if (!(offset >= -128 && offset <= 127))
379				return false;
380
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;
424			}
425
426			return true;
427		}
428
429		static void ComputeOffsets (MethodBody body)
430		{
431			var offset = 0;
432			foreach (var instruction in body.Instructions) {
433				instruction.Offset = offset;
434				offset += instruction.GetSize ();
435			}
436		}
437
438		public static ParameterDefinition GetParameter (this MethodBody self, int index)
439		{
440			var method = self.Method;
441
442			if (method.HasThis) {
443				if (index == 0)
444					return self.ThisParameter;
445
446				index--;
447			}
448
449			var parameters = method.Parameters;
450
451			if (index < 0 || index >= parameters.Count)
452				return null;
453
454			return parameters [index];
455		}
456
457		public static bool Implements (this TypeReference self, string interfaceName)
458		{
459			if (interfaceName == null)
460				throw new ArgumentNullException ("interfaceName");
461			if (self == null)
462				return false;
463
464			TypeDefinition type = self.Resolve ();
465			if (type == null)
466				return false;	// not enough information available
467
468			// special case, check if we implement ourselves
469			if (type.IsInterface && (type.FullName == interfaceName))
470				return true;
471
472			return Implements (type, interfaceName, (interfaceName.IndexOf ('`') >= 0));
473		}
474
475		public static bool Implements (TypeDefinition type, string interfaceName, bool generic)
476		{
477			while (type != null) {
478				// does the type implements it itself
479				if (type.HasInterfaces) {
480					foreach (TypeReference iface in type.Interfaces) {
481						string fullname = (generic) ? iface.GetElementType ().FullName : iface.FullName;
482						if (fullname == interfaceName)
483							return true;
484						//if not, then maybe one of its parent interfaces does
485						if (Implements (iface.Resolve (), interfaceName, generic))
486							return true;
487					}
488				}
489
490				type = type.BaseType != null ? type.BaseType.Resolve () : null;
491			}
492			return false;
493		}
494
495		public static bool Inherits (this TypeReference self, string className)
496		{
497			if (className == null)
498				throw new ArgumentNullException ("className");
499			if (self == null)
500				return false;
501
502			TypeReference current = self.Resolve ();
503			while (current != null) {
504				string fullname = current.FullName;
505				if (fullname == className)
506					return true;
507				if (fullname == "System.Object")
508					return false;
509
510				TypeDefinition td = current.Resolve ();
511				if (td == null)
512					return false;		// could not resolve type
513				current = td.BaseType;
514			}
515			return false;
516		}
517	}
518}