PageRenderTime 73ms CodeModel.GetById 37ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

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

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