PageRenderTime 32ms CodeModel.GetById 11ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/Mono.Cecil/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs

http://github.com/icsharpcode/ILSpy
C# | 407 lines | 359 code | 21 blank | 27 comment | 37 complexity | 09d0cd478e18d333bbcf8d1c9846883a 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;
 30
 31using Mono.Cecil.Cil;
 32
 33namespace Mono.Cecil.Rocks {
 34
 35#if INSIDE_ROCKS
 36	public
 37#endif
 38	static class MethodBodyRocks {
 39
 40		public static void SimplifyMacros (this MethodBody self)
 41		{
 42			if (self == null)
 43				throw new ArgumentNullException ("self");
 44
 45			foreach (var instruction in self.Instructions) {
 46				if (instruction.OpCode.OpCodeType != OpCodeType.Macro)
 47					continue;
 48
 49				switch (instruction.OpCode.Code) {
 50				case Code.Ldarg_0:
 51					ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (0));
 52					break;
 53				case Code.Ldarg_1:
 54					ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (1));
 55					break;
 56				case Code.Ldarg_2:
 57					ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (2));
 58					break;
 59				case Code.Ldarg_3:
 60					ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (3));
 61					break;
 62				case Code.Ldloc_0:
 63					ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [0]);
 64					break;
 65				case Code.Ldloc_1:
 66					ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [1]);
 67					break;
 68				case Code.Ldloc_2:
 69					ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [2]);
 70					break;
 71				case Code.Ldloc_3:
 72					ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [3]);
 73					break;
 74				case Code.Stloc_0:
 75					ExpandMacro (instruction, OpCodes.Stloc, self.Variables [0]);
 76					break;
 77				case Code.Stloc_1:
 78					ExpandMacro (instruction, OpCodes.Stloc, self.Variables [1]);
 79					break;
 80				case Code.Stloc_2:
 81					ExpandMacro (instruction, OpCodes.Stloc, self.Variables [2]);
 82					break;
 83				case Code.Stloc_3:
 84					ExpandMacro (instruction, OpCodes.Stloc, self.Variables [3]);
 85					break;
 86				case Code.Ldarg_S:
 87					instruction.OpCode = OpCodes.Ldarg;
 88					break;
 89				case Code.Ldarga_S:
 90					instruction.OpCode = OpCodes.Ldarga;
 91					break;
 92				case Code.Starg_S:
 93					instruction.OpCode = OpCodes.Starg;
 94					break;
 95				case Code.Ldloc_S:
 96					instruction.OpCode = OpCodes.Ldloc;
 97					break;
 98				case Code.Ldloca_S:
 99					instruction.OpCode = OpCodes.Ldloca;
100					break;
101				case Code.Stloc_S:
102					instruction.OpCode = OpCodes.Stloc;
103					break;
104				case Code.Ldc_I4_M1:
105					ExpandMacro (instruction, OpCodes.Ldc_I4, -1);
106					break;
107				case Code.Ldc_I4_0:
108					ExpandMacro (instruction, OpCodes.Ldc_I4, 0);
109					break;
110				case Code.Ldc_I4_1:
111					ExpandMacro (instruction, OpCodes.Ldc_I4, 1);
112					break;
113				case Code.Ldc_I4_2:
114					ExpandMacro (instruction, OpCodes.Ldc_I4, 2);
115					break;
116				case Code.Ldc_I4_3:
117					ExpandMacro (instruction, OpCodes.Ldc_I4, 3);
118					break;
119				case Code.Ldc_I4_4:
120					ExpandMacro (instruction, OpCodes.Ldc_I4, 4);
121					break;
122				case Code.Ldc_I4_5:
123					ExpandMacro (instruction, OpCodes.Ldc_I4, 5);
124					break;
125				case Code.Ldc_I4_6:
126					ExpandMacro (instruction, OpCodes.Ldc_I4, 6);
127					break;
128				case Code.Ldc_I4_7:
129					ExpandMacro (instruction, OpCodes.Ldc_I4, 7);
130					break;
131				case Code.Ldc_I4_8:
132					ExpandMacro (instruction, OpCodes.Ldc_I4, 8);
133					break;
134				case Code.Ldc_I4_S:
135					ExpandMacro (instruction, OpCodes.Ldc_I4, (int) (sbyte) instruction.Operand);
136					break;
137				case Code.Br_S:
138					instruction.OpCode = OpCodes.Br;
139					break;
140				case Code.Brfalse_S:
141					instruction.OpCode = OpCodes.Brfalse;
142					break;
143				case Code.Brtrue_S:
144					instruction.OpCode = OpCodes.Brtrue;
145					break;
146				case Code.Beq_S:
147					instruction.OpCode = OpCodes.Beq;
148					break;
149				case Code.Bge_S:
150					instruction.OpCode = OpCodes.Bge;
151					break;
152				case Code.Bgt_S:
153					instruction.OpCode = OpCodes.Bgt;
154					break;
155				case Code.Ble_S:
156					instruction.OpCode = OpCodes.Ble;
157					break;
158				case Code.Blt_S:
159					instruction.OpCode = OpCodes.Blt;
160					break;
161				case Code.Bne_Un_S:
162					instruction.OpCode = OpCodes.Bne_Un;
163					break;
164				case Code.Bge_Un_S:
165					instruction.OpCode = OpCodes.Bge_Un;
166					break;
167				case Code.Bgt_Un_S:
168					instruction.OpCode = OpCodes.Bgt_Un;
169					break;
170				case Code.Ble_Un_S:
171					instruction.OpCode = OpCodes.Ble_Un;
172					break;
173				case Code.Blt_Un_S:
174					instruction.OpCode = OpCodes.Blt_Un;
175					break;
176				case Code.Leave_S:
177					instruction.OpCode = OpCodes.Leave;
178					break;
179				}
180			}
181		}
182
183		static void ExpandMacro (Instruction instruction, OpCode opcode, object operand)
184		{
185			instruction.OpCode = opcode;
186			instruction.Operand = operand;
187		}
188
189		static void MakeMacro (Instruction instruction, OpCode opcode)
190		{
191			instruction.OpCode = opcode;
192			instruction.Operand = null;
193		}
194
195		public static void OptimizeMacros (this MethodBody self)
196		{
197			if (self == null)
198				throw new ArgumentNullException ("self");
199
200			var method = self.Method;
201
202			foreach (var instruction in self.Instructions) {
203				int index;
204				switch (instruction.OpCode.Code) {
205				case Code.Ldarg:
206					index = ((ParameterDefinition) instruction.Operand).Index;
207					if (index == -1 && instruction.Operand == self.ThisParameter)
208						index = 0;
209					else if (method.HasThis)
210						index++;
211
212					switch (index) {
213					case 0:
214						MakeMacro (instruction, OpCodes.Ldarg_0);
215						break;
216					case 1:
217						MakeMacro (instruction, OpCodes.Ldarg_1);
218						break;
219					case 2:
220						MakeMacro (instruction, OpCodes.Ldarg_2);
221						break;
222					case 3:
223						MakeMacro (instruction, OpCodes.Ldarg_3);
224						break;
225					default:
226						if (index < 256)
227							ExpandMacro (instruction, OpCodes.Ldarg_S, instruction.Operand);
228						break;
229					}
230					break;
231				case Code.Ldloc:
232					index = ((VariableDefinition) instruction.Operand).Index;
233					switch (index) {
234					case 0:
235						MakeMacro (instruction, OpCodes.Ldloc_0);
236						break;
237					case 1:
238						MakeMacro (instruction, OpCodes.Ldloc_1);
239						break;
240					case 2:
241						MakeMacro (instruction, OpCodes.Ldloc_2);
242						break;
243					case 3:
244						MakeMacro (instruction, OpCodes.Ldloc_3);
245						break;
246					default:
247						if (index < 256)
248							ExpandMacro (instruction, OpCodes.Ldloc_S, instruction.Operand);
249						break;
250					}
251					break;
252				case Code.Stloc:
253					index = ((VariableDefinition) instruction.Operand).Index;
254					switch (index) {
255					case 0:
256						MakeMacro (instruction, OpCodes.Stloc_0);
257						break;
258					case 1:
259						MakeMacro (instruction, OpCodes.Stloc_1);
260						break;
261					case 2:
262						MakeMacro (instruction, OpCodes.Stloc_2);
263						break;
264					case 3:
265						MakeMacro (instruction, OpCodes.Stloc_3);
266						break;
267					default:
268						if (index < 256)
269							ExpandMacro (instruction, OpCodes.Stloc_S, instruction.Operand);
270						break;
271					}
272					break;
273				case Code.Ldarga:
274					index = ((ParameterDefinition) instruction.Operand).Index;
275					if (index == -1 && instruction.Operand == self.ThisParameter)
276						index = 0;
277					else if (method.HasThis)
278						index++;
279					if (index < 256)
280						ExpandMacro (instruction, OpCodes.Ldarga_S, instruction.Operand);
281					break;
282				case Code.Ldloca:
283					if (((VariableDefinition) instruction.Operand).Index < 256)
284						ExpandMacro (instruction, OpCodes.Ldloca_S, instruction.Operand);
285					break;
286				case Code.Ldc_I4:
287					int i = (int) instruction.Operand;
288					switch (i) {
289					case -1:
290						MakeMacro (instruction, OpCodes.Ldc_I4_M1);
291						break;
292					case 0:
293						MakeMacro (instruction, OpCodes.Ldc_I4_0);
294						break;
295					case 1:
296						MakeMacro (instruction, OpCodes.Ldc_I4_1);
297						break;
298					case 2:
299						MakeMacro (instruction, OpCodes.Ldc_I4_2);
300						break;
301					case 3:
302						MakeMacro (instruction, OpCodes.Ldc_I4_3);
303						break;
304					case 4:
305						MakeMacro (instruction, OpCodes.Ldc_I4_4);
306						break;
307					case 5:
308						MakeMacro (instruction, OpCodes.Ldc_I4_5);
309						break;
310					case 6:
311						MakeMacro (instruction, OpCodes.Ldc_I4_6);
312						break;
313					case 7:
314						MakeMacro (instruction, OpCodes.Ldc_I4_7);
315						break;
316					case 8:
317						MakeMacro (instruction, OpCodes.Ldc_I4_8);
318						break;
319					default:
320						if (i >= -128 && i < 128)
321							ExpandMacro (instruction, OpCodes.Ldc_I4_S, (sbyte) i);
322						break;
323					}
324					break;
325				}
326			}
327
328			OptimizeBranches (self);
329		}
330
331		static void OptimizeBranches (MethodBody body)
332		{
333			ComputeOffsets (body);
334
335			foreach (var instruction in body.Instructions) {
336				if (instruction.OpCode.OperandType != OperandType.InlineBrTarget)
337					continue;
338
339				if (OptimizeBranch (instruction))
340					ComputeOffsets (body);
341			}
342		}
343
344		static bool OptimizeBranch (Instruction instruction)
345		{
346			var offset = ((Instruction) instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4);
347			if (!(offset >= -128 && offset <= 127))
348				return false;
349
350			switch (instruction.OpCode.Code) {
351			case Code.Br:
352				instruction.OpCode = OpCodes.Br_S;
353				break;
354			case Code.Brfalse:
355				instruction.OpCode = OpCodes.Brfalse_S;
356				break;
357			case Code.Brtrue:
358				instruction.OpCode = OpCodes.Brtrue_S;
359				break;
360			case Code.Beq:
361				instruction.OpCode = OpCodes.Beq_S;
362				break;
363			case Code.Bge:
364				instruction.OpCode = OpCodes.Bge_S;
365				break;
366			case Code.Bgt:
367				instruction.OpCode = OpCodes.Bgt_S;
368				break;
369			case Code.Ble:
370				instruction.OpCode = OpCodes.Ble_S;
371				break;
372			case Code.Blt:
373				instruction.OpCode = OpCodes.Blt_S;
374				break;
375			case Code.Bne_Un:
376				instruction.OpCode = OpCodes.Bne_Un_S;
377				break;
378			case Code.Bge_Un:
379				instruction.OpCode = OpCodes.Bge_Un_S;
380				break;
381			case Code.Bgt_Un:
382				instruction.OpCode = OpCodes.Bgt_Un_S;
383				break;
384			case Code.Ble_Un:
385				instruction.OpCode = OpCodes.Ble_Un_S;
386				break;
387			case Code.Blt_Un:
388				instruction.OpCode = OpCodes.Blt_Un_S;
389				break;
390			case Code.Leave:
391				instruction.OpCode = OpCodes.Leave_S;
392				break;
393			}
394
395			return true;
396		}
397
398		static void ComputeOffsets (MethodBody body)
399		{
400			var offset = 0;
401			foreach (var instruction in body.Instructions) {
402				instruction.Offset = offset;
403				offset += instruction.GetSize ();
404			}
405		}
406	}
407}