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