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