PageRenderTime 172ms CodeModel.GetById 48ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/tools/tuner/Mono.Tuner/CecilRocks.cs

https://github.com/hollow87/mono
C# | 518 lines | 445 code | 43 blank | 30 comment | 71 complexity | 2215dd00e8ffba42e597aad594c19fb1 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 System.Collections.Generic;
  30. using System.Linq;
  31. using Mono.Cecil;
  32. using Mono.Cecil.Cil;
  33. namespace Mono.Tuner {
  34. public static class MethodBodyRocks {
  35. public static IEnumerable<TypeDefinition> GetAllTypes (this ModuleDefinition self)
  36. {
  37. return self.Types.SelectMany (t => t.GetAllTypes ());
  38. }
  39. static IEnumerable<TypeDefinition> GetAllTypes (this TypeDefinition self)
  40. {
  41. yield return self;
  42. if (!self.HasNestedTypes)
  43. yield break;
  44. foreach (var type in self.NestedTypes.SelectMany (t => t.GetAllTypes ()))
  45. yield return type;
  46. }
  47. public static IEnumerable<MethodDefinition> GetMethods (this TypeDefinition self)
  48. {
  49. return self.Methods.Where (m => !m.IsConstructor);
  50. }
  51. public static IEnumerable<MethodDefinition> GetConstructors (this TypeDefinition self)
  52. {
  53. return self.Methods.Where (m => m.IsConstructor);
  54. }
  55. public static MethodDefinition GetTypeConstructor (this TypeDefinition self)
  56. {
  57. return self.GetConstructors ().FirstOrDefault (c => c.IsStatic);
  58. }
  59. public static void SimplifyMacros (this MethodBody self)
  60. {
  61. if (self == null)
  62. throw new ArgumentNullException ("self");
  63. foreach (var instruction in self.Instructions) {
  64. if (instruction.OpCode.OpCodeType != OpCodeType.Macro)
  65. continue;
  66. switch (instruction.OpCode.Code) {
  67. case Code.Ldarg_0:
  68. ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (0));
  69. break;
  70. case Code.Ldarg_1:
  71. ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (1));
  72. break;
  73. case Code.Ldarg_2:
  74. ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (2));
  75. break;
  76. case Code.Ldarg_3:
  77. ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (3));
  78. break;
  79. case Code.Ldloc_0:
  80. ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [0]);
  81. break;
  82. case Code.Ldloc_1:
  83. ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [1]);
  84. break;
  85. case Code.Ldloc_2:
  86. ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [2]);
  87. break;
  88. case Code.Ldloc_3:
  89. ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [3]);
  90. break;
  91. case Code.Stloc_0:
  92. ExpandMacro (instruction, OpCodes.Stloc, self.Variables [0]);
  93. break;
  94. case Code.Stloc_1:
  95. ExpandMacro (instruction, OpCodes.Stloc, self.Variables [1]);
  96. break;
  97. case Code.Stloc_2:
  98. ExpandMacro (instruction, OpCodes.Stloc, self.Variables [2]);
  99. break;
  100. case Code.Stloc_3:
  101. ExpandMacro (instruction, OpCodes.Stloc, self.Variables [3]);
  102. break;
  103. case Code.Ldarg_S:
  104. instruction.OpCode = OpCodes.Ldarg;
  105. break;
  106. case Code.Ldarga_S:
  107. instruction.OpCode = OpCodes.Ldarga;
  108. break;
  109. case Code.Starg_S:
  110. instruction.OpCode = OpCodes.Starg;
  111. break;
  112. case Code.Ldloc_S:
  113. instruction.OpCode = OpCodes.Ldloc;
  114. break;
  115. case Code.Ldloca_S:
  116. instruction.OpCode = OpCodes.Ldloca;
  117. break;
  118. case Code.Stloc_S:
  119. instruction.OpCode = OpCodes.Stloc;
  120. break;
  121. case Code.Ldc_I4_M1:
  122. ExpandMacro (instruction, OpCodes.Ldc_I4, -1);
  123. break;
  124. case Code.Ldc_I4_0:
  125. ExpandMacro (instruction, OpCodes.Ldc_I4, 0);
  126. break;
  127. case Code.Ldc_I4_1:
  128. ExpandMacro (instruction, OpCodes.Ldc_I4, 1);
  129. break;
  130. case Code.Ldc_I4_2:
  131. ExpandMacro (instruction, OpCodes.Ldc_I4, 2);
  132. break;
  133. case Code.Ldc_I4_3:
  134. ExpandMacro (instruction, OpCodes.Ldc_I4, 3);
  135. break;
  136. case Code.Ldc_I4_4:
  137. ExpandMacro (instruction, OpCodes.Ldc_I4, 4);
  138. break;
  139. case Code.Ldc_I4_5:
  140. ExpandMacro (instruction, OpCodes.Ldc_I4, 5);
  141. break;
  142. case Code.Ldc_I4_6:
  143. ExpandMacro (instruction, OpCodes.Ldc_I4, 6);
  144. break;
  145. case Code.Ldc_I4_7:
  146. ExpandMacro (instruction, OpCodes.Ldc_I4, 7);
  147. break;
  148. case Code.Ldc_I4_8:
  149. ExpandMacro (instruction, OpCodes.Ldc_I4, 8);
  150. break;
  151. case Code.Ldc_I4_S:
  152. ExpandMacro (instruction, OpCodes.Ldc_I4, (int) (sbyte) instruction.Operand);
  153. break;
  154. case Code.Br_S:
  155. instruction.OpCode = OpCodes.Br;
  156. break;
  157. case Code.Brfalse_S:
  158. instruction.OpCode = OpCodes.Brfalse;
  159. break;
  160. case Code.Brtrue_S:
  161. instruction.OpCode = OpCodes.Brtrue;
  162. break;
  163. case Code.Beq_S:
  164. instruction.OpCode = OpCodes.Beq;
  165. break;
  166. case Code.Bge_S:
  167. instruction.OpCode = OpCodes.Bge;
  168. break;
  169. case Code.Bgt_S:
  170. instruction.OpCode = OpCodes.Bgt;
  171. break;
  172. case Code.Ble_S:
  173. instruction.OpCode = OpCodes.Ble;
  174. break;
  175. case Code.Blt_S:
  176. instruction.OpCode = OpCodes.Blt;
  177. break;
  178. case Code.Bne_Un_S:
  179. instruction.OpCode = OpCodes.Bne_Un;
  180. break;
  181. case Code.Bge_Un_S:
  182. instruction.OpCode = OpCodes.Bge_Un;
  183. break;
  184. case Code.Bgt_Un_S:
  185. instruction.OpCode = OpCodes.Bgt_Un;
  186. break;
  187. case Code.Ble_Un_S:
  188. instruction.OpCode = OpCodes.Ble_Un;
  189. break;
  190. case Code.Blt_Un_S:
  191. instruction.OpCode = OpCodes.Blt_Un;
  192. break;
  193. case Code.Leave_S:
  194. instruction.OpCode = OpCodes.Leave;
  195. break;
  196. }
  197. }
  198. }
  199. static void ExpandMacro (Instruction instruction, OpCode opcode, object operand)
  200. {
  201. instruction.OpCode = opcode;
  202. instruction.Operand = operand;
  203. }
  204. static void MakeMacro (Instruction instruction, OpCode opcode)
  205. {
  206. instruction.OpCode = opcode;
  207. instruction.Operand = null;
  208. }
  209. public static void OptimizeMacros (this MethodBody self)
  210. {
  211. if (self == null)
  212. throw new ArgumentNullException ("self");
  213. var method = self.Method;
  214. foreach (var instruction in self.Instructions) {
  215. int index;
  216. switch (instruction.OpCode.Code) {
  217. case Code.Ldarg:
  218. index = ((ParameterDefinition) instruction.Operand).Index;
  219. if (index == -1 && instruction.Operand == self.ThisParameter)
  220. index = 0;
  221. else if (method.HasThis)
  222. index++;
  223. switch (index) {
  224. case 0:
  225. MakeMacro (instruction, OpCodes.Ldarg_0);
  226. break;
  227. case 1:
  228. MakeMacro (instruction, OpCodes.Ldarg_1);
  229. break;
  230. case 2:
  231. MakeMacro (instruction, OpCodes.Ldarg_2);
  232. break;
  233. case 3:
  234. MakeMacro (instruction, OpCodes.Ldarg_3);
  235. break;
  236. default:
  237. if (index < 256)
  238. ExpandMacro (instruction, OpCodes.Ldarg_S, instruction.Operand);
  239. break;
  240. }
  241. break;
  242. case Code.Ldloc:
  243. index = ((VariableDefinition) instruction.Operand).Index;
  244. switch (index) {
  245. case 0:
  246. MakeMacro (instruction, OpCodes.Ldloc_0);
  247. break;
  248. case 1:
  249. MakeMacro (instruction, OpCodes.Ldloc_1);
  250. break;
  251. case 2:
  252. MakeMacro (instruction, OpCodes.Ldloc_2);
  253. break;
  254. case 3:
  255. MakeMacro (instruction, OpCodes.Ldloc_3);
  256. break;
  257. default:
  258. if (index < 256)
  259. ExpandMacro (instruction, OpCodes.Ldloc_S, instruction.Operand);
  260. break;
  261. }
  262. break;
  263. case Code.Stloc:
  264. index = ((VariableDefinition) instruction.Operand).Index;
  265. switch (index) {
  266. case 0:
  267. MakeMacro (instruction, OpCodes.Stloc_0);
  268. break;
  269. case 1:
  270. MakeMacro (instruction, OpCodes.Stloc_1);
  271. break;
  272. case 2:
  273. MakeMacro (instruction, OpCodes.Stloc_2);
  274. break;
  275. case 3:
  276. MakeMacro (instruction, OpCodes.Stloc_3);
  277. break;
  278. default:
  279. if (index < 256)
  280. ExpandMacro (instruction, OpCodes.Stloc_S, instruction.Operand);
  281. break;
  282. }
  283. break;
  284. case Code.Ldarga:
  285. index = ((ParameterDefinition) instruction.Operand).Index;
  286. if (index == -1 && instruction.Operand == self.ThisParameter)
  287. index = 0;
  288. else if (method.HasThis)
  289. index++;
  290. if (index < 256)
  291. ExpandMacro (instruction, OpCodes.Ldarga_S, instruction.Operand);
  292. break;
  293. case Code.Ldloca:
  294. if (((VariableDefinition) instruction.Operand).Index < 256)
  295. ExpandMacro (instruction, OpCodes.Ldloca_S, instruction.Operand);
  296. break;
  297. case Code.Ldc_I4:
  298. int i = (int) instruction.Operand;
  299. switch (i) {
  300. case -1:
  301. MakeMacro (instruction, OpCodes.Ldc_I4_M1);
  302. break;
  303. case 0:
  304. MakeMacro (instruction, OpCodes.Ldc_I4_0);
  305. break;
  306. case 1:
  307. MakeMacro (instruction, OpCodes.Ldc_I4_1);
  308. break;
  309. case 2:
  310. MakeMacro (instruction, OpCodes.Ldc_I4_2);
  311. break;
  312. case 3:
  313. MakeMacro (instruction, OpCodes.Ldc_I4_3);
  314. break;
  315. case 4:
  316. MakeMacro (instruction, OpCodes.Ldc_I4_4);
  317. break;
  318. case 5:
  319. MakeMacro (instruction, OpCodes.Ldc_I4_5);
  320. break;
  321. case 6:
  322. MakeMacro (instruction, OpCodes.Ldc_I4_6);
  323. break;
  324. case 7:
  325. MakeMacro (instruction, OpCodes.Ldc_I4_7);
  326. break;
  327. case 8:
  328. MakeMacro (instruction, OpCodes.Ldc_I4_8);
  329. break;
  330. default:
  331. if (i >= -128 && i < 128)
  332. ExpandMacro (instruction, OpCodes.Ldc_I4_S, (sbyte) i);
  333. break;
  334. }
  335. break;
  336. }
  337. }
  338. OptimizeBranches (self);
  339. }
  340. static void OptimizeBranches (MethodBody body)
  341. {
  342. ComputeOffsets (body);
  343. foreach (var instruction in body.Instructions) {
  344. if (instruction.OpCode.OperandType != OperandType.InlineBrTarget)
  345. continue;
  346. if (OptimizeBranch (instruction))
  347. ComputeOffsets (body);
  348. }
  349. }
  350. static bool OptimizeBranch (Instruction instruction)
  351. {
  352. var offset = ((Instruction) instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4);
  353. if (!(offset >= -128 && offset <= 127))
  354. return false;
  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. return true;
  400. }
  401. static void ComputeOffsets (MethodBody body)
  402. {
  403. var offset = 0;
  404. foreach (var instruction in body.Instructions) {
  405. instruction.Offset = offset;
  406. offset += instruction.GetSize ();
  407. }
  408. }
  409. public static ParameterDefinition GetParameter (this MethodBody self, int index)
  410. {
  411. var method = self.Method;
  412. if (method.HasThis) {
  413. if (index == 0)
  414. return self.ThisParameter;
  415. index--;
  416. }
  417. var parameters = method.Parameters;
  418. if (index < 0 || index >= parameters.Count)
  419. return null;
  420. return parameters [index];
  421. }
  422. public static bool Implements (this TypeReference self, string interfaceName)
  423. {
  424. if (interfaceName == null)
  425. throw new ArgumentNullException ("interfaceName");
  426. if (self == null)
  427. return false;
  428. TypeDefinition type = self.Resolve ();
  429. if (type == null)
  430. return false; // not enough information available
  431. // special case, check if we implement ourselves
  432. if (type.IsInterface && (type.FullName == interfaceName))
  433. return true;
  434. return Implements (type, interfaceName, (interfaceName.IndexOf ('`') >= 0));
  435. }
  436. public static bool Implements (TypeDefinition type, string interfaceName, bool generic)
  437. {
  438. while (type != null) {
  439. // does the type implements it itself
  440. if (type.HasInterfaces) {
  441. foreach (TypeReference iface in type.Interfaces) {
  442. string fullname = (generic) ? iface.GetElementType ().FullName : iface.FullName;
  443. if (fullname == interfaceName)
  444. return true;
  445. //if not, then maybe one of its parent interfaces does
  446. if (Implements (iface.Resolve (), interfaceName, generic))
  447. return true;
  448. }
  449. }
  450. type = type.BaseType != null ? type.BaseType.Resolve () : null;
  451. }
  452. return false;
  453. }
  454. public static bool Inherits (this TypeReference self, string className)
  455. {
  456. if (className == null)
  457. throw new ArgumentNullException ("className");
  458. if (self == null)
  459. return false;
  460. TypeReference current = self.Resolve ();
  461. while (current != null) {
  462. string fullname = current.FullName;
  463. if (fullname == className)
  464. return true;
  465. if (fullname == "System.Object")
  466. return false;
  467. TypeDefinition td = current.Resolve ();
  468. if (td == null)
  469. return false; // could not resolve type
  470. current = td.BaseType;
  471. }
  472. return false;
  473. }
  474. }
  475. }