/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

http://github.com/icsharpcode/ILSpy · C# · 600 lines · 509 code · 67 blank · 24 comment · 116 complexity · 88e3686a1c87e6e7a2065a73b1769d4d MD5 · raw file

  1. // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Diagnostics;
  21. using System.IO;
  22. using System.Linq;
  23. using System.Text;
  24. using ICSharpCode.Decompiler;
  25. using ICSharpCode.Decompiler.Disassembler;
  26. using ICSharpCode.NRefactory.Utils;
  27. using Mono.Cecil;
  28. using Mono.Cecil.Cil;
  29. using Cecil = Mono.Cecil;
  30. namespace ICSharpCode.Decompiler.ILAst
  31. {
  32. public abstract class ILNode
  33. {
  34. public IEnumerable<T> GetSelfAndChildrenRecursive<T>(Func<T, bool> predicate = null) where T: ILNode
  35. {
  36. List<T> result = new List<T>(16);
  37. AccumulateSelfAndChildrenRecursive(result, predicate);
  38. return result;
  39. }
  40. void AccumulateSelfAndChildrenRecursive<T>(List<T> list, Func<T, bool> predicate) where T:ILNode
  41. {
  42. // Note: RemoveEndFinally depends on self coming before children
  43. T thisAsT = this as T;
  44. if (thisAsT != null && (predicate == null || predicate(thisAsT)))
  45. list.Add(thisAsT);
  46. foreach (ILNode node in this.GetChildren()) {
  47. if (node != null)
  48. node.AccumulateSelfAndChildrenRecursive(list, predicate);
  49. }
  50. }
  51. public virtual IEnumerable<ILNode> GetChildren()
  52. {
  53. yield break;
  54. }
  55. public override string ToString()
  56. {
  57. StringWriter w = new StringWriter();
  58. WriteTo(new PlainTextOutput(w));
  59. return w.ToString().Replace("\r\n", "; ");
  60. }
  61. public abstract void WriteTo(ITextOutput output);
  62. }
  63. public class ILBlock: ILNode
  64. {
  65. public ILExpression EntryGoto;
  66. public List<ILNode> Body;
  67. public ILBlock(params ILNode[] body)
  68. {
  69. this.Body = new List<ILNode>(body);
  70. }
  71. public ILBlock(List<ILNode> body)
  72. {
  73. this.Body = body;
  74. }
  75. public override IEnumerable<ILNode> GetChildren()
  76. {
  77. if (this.EntryGoto != null)
  78. yield return this.EntryGoto;
  79. foreach(ILNode child in this.Body) {
  80. yield return child;
  81. }
  82. }
  83. public override void WriteTo(ITextOutput output)
  84. {
  85. foreach(ILNode child in this.GetChildren()) {
  86. child.WriteTo(output);
  87. output.WriteLine();
  88. }
  89. }
  90. }
  91. public class ILBasicBlock: ILNode
  92. {
  93. /// <remarks> Body has to start with a label and end with unconditional control flow </remarks>
  94. public List<ILNode> Body = new List<ILNode>();
  95. public override IEnumerable<ILNode> GetChildren()
  96. {
  97. return this.Body;
  98. }
  99. public override void WriteTo(ITextOutput output)
  100. {
  101. foreach(ILNode child in this.GetChildren()) {
  102. child.WriteTo(output);
  103. output.WriteLine();
  104. }
  105. }
  106. }
  107. public class ILLabel: ILNode
  108. {
  109. public string Name;
  110. public override void WriteTo(ITextOutput output)
  111. {
  112. output.WriteDefinition(Name + ":", this);
  113. }
  114. }
  115. public class ILTryCatchBlock: ILNode
  116. {
  117. public class CatchBlock: ILBlock
  118. {
  119. public TypeReference ExceptionType;
  120. public ILVariable ExceptionVariable;
  121. public override void WriteTo(ITextOutput output)
  122. {
  123. output.Write("catch ");
  124. output.WriteReference(ExceptionType.FullName, ExceptionType);
  125. if (ExceptionVariable != null) {
  126. output.Write(' ');
  127. output.Write(ExceptionVariable.Name);
  128. }
  129. output.WriteLine(" {");
  130. output.Indent();
  131. base.WriteTo(output);
  132. output.Unindent();
  133. output.WriteLine("}");
  134. }
  135. }
  136. public ILBlock TryBlock;
  137. public List<CatchBlock> CatchBlocks;
  138. public ILBlock FinallyBlock;
  139. public ILBlock FaultBlock;
  140. public override IEnumerable<ILNode> GetChildren()
  141. {
  142. if (this.TryBlock != null)
  143. yield return this.TryBlock;
  144. foreach (var catchBlock in this.CatchBlocks) {
  145. yield return catchBlock;
  146. }
  147. if (this.FaultBlock != null)
  148. yield return this.FaultBlock;
  149. if (this.FinallyBlock != null)
  150. yield return this.FinallyBlock;
  151. }
  152. public override void WriteTo(ITextOutput output)
  153. {
  154. output.WriteLine(".try {");
  155. output.Indent();
  156. TryBlock.WriteTo(output);
  157. output.Unindent();
  158. output.WriteLine("}");
  159. foreach (CatchBlock block in CatchBlocks) {
  160. block.WriteTo(output);
  161. }
  162. if (FaultBlock != null) {
  163. output.WriteLine("fault {");
  164. output.Indent();
  165. FaultBlock.WriteTo(output);
  166. output.Unindent();
  167. output.WriteLine("}");
  168. }
  169. if (FinallyBlock != null) {
  170. output.WriteLine("finally {");
  171. output.Indent();
  172. FinallyBlock.WriteTo(output);
  173. output.Unindent();
  174. output.WriteLine("}");
  175. }
  176. }
  177. }
  178. public class ILVariable
  179. {
  180. public string Name;
  181. public bool IsGenerated;
  182. public TypeReference Type;
  183. public VariableDefinition OriginalVariable;
  184. public ParameterDefinition OriginalParameter;
  185. public bool IsPinned {
  186. get { return OriginalVariable != null && OriginalVariable.IsPinned; }
  187. }
  188. public bool IsParameter {
  189. get { return OriginalParameter != null; }
  190. }
  191. public override string ToString()
  192. {
  193. return Name;
  194. }
  195. }
  196. public struct ILRange
  197. {
  198. public readonly int From;
  199. public readonly int To; // Exlusive
  200. public ILRange(int @from, int to)
  201. {
  202. this.From = @from;
  203. this.To = to;
  204. }
  205. public override string ToString()
  206. {
  207. return string.Format("{0:X2}-{1:X2}", From, To);
  208. }
  209. public static List<ILRange> OrderAndJoin(IEnumerable<ILRange> input)
  210. {
  211. if (input == null)
  212. throw new ArgumentNullException("Input is null!");
  213. List<ILRange> result = new List<ILRange>();
  214. foreach(ILRange curr in input.OrderBy(r => r.From)) {
  215. if (result.Count > 0) {
  216. // Merge consequtive ranges if possible
  217. ILRange last = result[result.Count - 1];
  218. if (curr.From <= last.To) {
  219. result[result.Count - 1] = new ILRange(last.From, Math.Max(last.To, curr.To));
  220. continue;
  221. }
  222. }
  223. result.Add(curr);
  224. }
  225. return result;
  226. }
  227. public static List<ILRange> Invert(IEnumerable<ILRange> input, int codeSize)
  228. {
  229. if (input == null)
  230. throw new ArgumentNullException("Input is null!");
  231. if (codeSize <= 0)
  232. throw new ArgumentException("Code size must be grater than 0");
  233. List<ILRange> ordered = OrderAndJoin(input);
  234. List<ILRange> result = new List<ILRange>(ordered.Count + 1);
  235. if (ordered.Count == 0) {
  236. result.Add(new ILRange(0, codeSize));
  237. } else {
  238. // Gap before the first element
  239. if (ordered.First().From != 0)
  240. result.Add(new ILRange(0, ordered.First().From));
  241. // Gaps between elements
  242. for (int i = 0; i < ordered.Count - 1; i++)
  243. result.Add(new ILRange(ordered[i].To, ordered[i + 1].From));
  244. // Gap after the last element
  245. Debug.Assert(ordered.Last().To <= codeSize);
  246. if (ordered.Last().To != codeSize)
  247. result.Add(new ILRange(ordered.Last().To, codeSize));
  248. }
  249. return result;
  250. }
  251. }
  252. public class ILExpressionPrefix
  253. {
  254. public readonly ILCode Code;
  255. public readonly object Operand;
  256. public ILExpressionPrefix(ILCode code, object operand = null)
  257. {
  258. this.Code = code;
  259. this.Operand = operand;
  260. }
  261. }
  262. public class ILExpression : ILNode
  263. {
  264. public ILCode Code { get; set; }
  265. public object Operand { get; set; }
  266. public List<ILExpression> Arguments { get; set; }
  267. public ILExpressionPrefix[] Prefixes { get; set; }
  268. // Mapping to the original instructions (useful for debugging)
  269. public List<ILRange> ILRanges { get; set; }
  270. public TypeReference ExpectedType { get; set; }
  271. public TypeReference InferredType { get; set; }
  272. public static readonly object AnyOperand = new object();
  273. public ILExpression(ILCode code, object operand, List<ILExpression> args)
  274. {
  275. if (operand is ILExpression)
  276. throw new ArgumentException("operand");
  277. this.Code = code;
  278. this.Operand = operand;
  279. this.Arguments = new List<ILExpression>(args);
  280. this.ILRanges = new List<ILRange>(1);
  281. }
  282. public ILExpression(ILCode code, object operand, params ILExpression[] args)
  283. {
  284. if (operand is ILExpression)
  285. throw new ArgumentException("operand");
  286. this.Code = code;
  287. this.Operand = operand;
  288. this.Arguments = new List<ILExpression>(args);
  289. this.ILRanges = new List<ILRange>(1);
  290. }
  291. public void AddPrefix(ILExpressionPrefix prefix)
  292. {
  293. ILExpressionPrefix[] arr = this.Prefixes;
  294. if (arr == null)
  295. arr = new ILExpressionPrefix[1];
  296. else
  297. Array.Resize(ref arr, arr.Length + 1);
  298. arr[arr.Length - 1] = prefix;
  299. this.Prefixes = arr;
  300. }
  301. public ILExpressionPrefix GetPrefix(ILCode code)
  302. {
  303. var prefixes = this.Prefixes;
  304. if (prefixes != null) {
  305. foreach (ILExpressionPrefix p in prefixes) {
  306. if (p.Code == code)
  307. return p;
  308. }
  309. }
  310. return null;
  311. }
  312. public override IEnumerable<ILNode> GetChildren()
  313. {
  314. return Arguments;
  315. }
  316. public bool IsBranch()
  317. {
  318. return this.Operand is ILLabel || this.Operand is ILLabel[];
  319. }
  320. public IEnumerable<ILLabel> GetBranchTargets()
  321. {
  322. if (this.Operand is ILLabel) {
  323. return new ILLabel[] { (ILLabel)this.Operand };
  324. } else if (this.Operand is ILLabel[]) {
  325. return (ILLabel[])this.Operand;
  326. } else {
  327. return new ILLabel[] { };
  328. }
  329. }
  330. public override void WriteTo(ITextOutput output)
  331. {
  332. if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) {
  333. if (Code == ILCode.Stloc && this.InferredType == null) {
  334. output.Write(((ILVariable)Operand).Name);
  335. output.Write(" = ");
  336. Arguments.First().WriteTo(output);
  337. return;
  338. } else if (Code == ILCode.Ldloc) {
  339. output.Write(((ILVariable)Operand).Name);
  340. if (this.InferredType != null) {
  341. output.Write(':');
  342. this.InferredType.WriteTo(output, ILNameSyntax.ShortTypeName);
  343. if (this.ExpectedType != null && this.ExpectedType.FullName != this.InferredType.FullName) {
  344. output.Write("[exp:");
  345. this.ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
  346. output.Write(']');
  347. }
  348. }
  349. return;
  350. }
  351. }
  352. if (this.Prefixes != null) {
  353. foreach (var prefix in this.Prefixes) {
  354. output.Write(prefix.Code.GetName());
  355. output.Write(". ");
  356. }
  357. }
  358. output.Write(Code.GetName());
  359. if (this.InferredType != null) {
  360. output.Write(':');
  361. this.InferredType.WriteTo(output, ILNameSyntax.ShortTypeName);
  362. if (this.ExpectedType != null && this.ExpectedType.FullName != this.InferredType.FullName) {
  363. output.Write("[exp:");
  364. this.ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
  365. output.Write(']');
  366. }
  367. } else if (this.ExpectedType != null) {
  368. output.Write("[exp:");
  369. this.ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
  370. output.Write(']');
  371. }
  372. output.Write('(');
  373. bool first = true;
  374. if (Operand != null) {
  375. if (Operand is ILLabel) {
  376. output.WriteReference(((ILLabel)Operand).Name, Operand);
  377. } else if (Operand is ILLabel[]) {
  378. ILLabel[] labels = (ILLabel[])Operand;
  379. for (int i = 0; i < labels.Length; i++) {
  380. if (i > 0)
  381. output.Write(", ");
  382. output.WriteReference(labels[i].Name, labels[i]);
  383. }
  384. } else if (Operand is MethodReference) {
  385. MethodReference method = (MethodReference)Operand;
  386. if (method.DeclaringType != null) {
  387. method.DeclaringType.WriteTo(output, ILNameSyntax.ShortTypeName);
  388. output.Write("::");
  389. }
  390. output.WriteReference(method.Name, method);
  391. } else if (Operand is FieldReference) {
  392. FieldReference field = (FieldReference)Operand;
  393. field.DeclaringType.WriteTo(output, ILNameSyntax.ShortTypeName);
  394. output.Write("::");
  395. output.WriteReference(field.Name, field);
  396. } else {
  397. DisassemblerHelpers.WriteOperand(output, Operand);
  398. }
  399. first = false;
  400. }
  401. foreach (ILExpression arg in this.Arguments) {
  402. if (!first) output.Write(", ");
  403. arg.WriteTo(output);
  404. first = false;
  405. }
  406. output.Write(')');
  407. }
  408. }
  409. public class ILWhileLoop : ILNode
  410. {
  411. public ILExpression Condition;
  412. public ILBlock BodyBlock;
  413. public override IEnumerable<ILNode> GetChildren()
  414. {
  415. if (this.Condition != null)
  416. yield return this.Condition;
  417. if (this.BodyBlock != null)
  418. yield return this.BodyBlock;
  419. }
  420. public override void WriteTo(ITextOutput output)
  421. {
  422. output.WriteLine("");
  423. output.Write("loop (");
  424. if (this.Condition != null)
  425. this.Condition.WriteTo(output);
  426. output.WriteLine(") {");
  427. output.Indent();
  428. this.BodyBlock.WriteTo(output);
  429. output.Unindent();
  430. output.WriteLine("}");
  431. }
  432. }
  433. public class ILCondition : ILNode
  434. {
  435. public ILExpression Condition;
  436. public ILBlock TrueBlock; // Branch was taken
  437. public ILBlock FalseBlock; // Fall-though
  438. public override IEnumerable<ILNode> GetChildren()
  439. {
  440. if (this.Condition != null)
  441. yield return this.Condition;
  442. if (this.TrueBlock != null)
  443. yield return this.TrueBlock;
  444. if (this.FalseBlock != null)
  445. yield return this.FalseBlock;
  446. }
  447. public override void WriteTo(ITextOutput output)
  448. {
  449. output.Write("if (");
  450. Condition.WriteTo(output);
  451. output.WriteLine(") {");
  452. output.Indent();
  453. TrueBlock.WriteTo(output);
  454. output.Unindent();
  455. output.Write("}");
  456. if (FalseBlock != null) {
  457. output.WriteLine(" else {");
  458. output.Indent();
  459. FalseBlock.WriteTo(output);
  460. output.Unindent();
  461. output.WriteLine("}");
  462. }
  463. }
  464. }
  465. public class ILSwitch: ILNode
  466. {
  467. public class CaseBlock: ILBlock
  468. {
  469. public List<int> Values; // null for the default case
  470. public override void WriteTo(ITextOutput output)
  471. {
  472. if (this.Values != null) {
  473. foreach (int i in this.Values) {
  474. output.WriteLine("case {0}:", i);
  475. }
  476. } else {
  477. output.WriteLine("default:");
  478. }
  479. output.Indent();
  480. base.WriteTo(output);
  481. output.Unindent();
  482. }
  483. }
  484. public ILExpression Condition;
  485. public List<CaseBlock> CaseBlocks = new List<CaseBlock>();
  486. public override IEnumerable<ILNode> GetChildren()
  487. {
  488. if (this.Condition != null)
  489. yield return this.Condition;
  490. foreach (ILBlock caseBlock in this.CaseBlocks) {
  491. yield return caseBlock;
  492. }
  493. }
  494. public override void WriteTo(ITextOutput output)
  495. {
  496. output.Write("switch (");
  497. Condition.WriteTo(output);
  498. output.WriteLine(") {");
  499. output.Indent();
  500. foreach (CaseBlock caseBlock in this.CaseBlocks) {
  501. caseBlock.WriteTo(output);
  502. }
  503. output.Unindent();
  504. output.WriteLine("}");
  505. }
  506. }
  507. public class ILFixedStatement : ILNode
  508. {
  509. public List<ILExpression> Initializers = new List<ILExpression>();
  510. public ILBlock BodyBlock;
  511. public override IEnumerable<ILNode> GetChildren()
  512. {
  513. foreach (ILExpression initializer in this.Initializers)
  514. yield return initializer;
  515. if (this.BodyBlock != null)
  516. yield return this.BodyBlock;
  517. }
  518. public override void WriteTo(ITextOutput output)
  519. {
  520. output.Write("fixed (");
  521. for (int i = 0; i < this.Initializers.Count; i++) {
  522. if (i > 0)
  523. output.Write(", ");
  524. this.Initializers[i].WriteTo(output);
  525. }
  526. output.WriteLine(") {");
  527. output.Indent();
  528. this.BodyBlock.WriteTo(output);
  529. output.Unindent();
  530. output.WriteLine("}");
  531. }
  532. }
  533. }