/rocks/Mono.Cecil.Rocks/MethodBodyRocks.cs
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}