summaryrefslogtreecommitdiff
path: root/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ICSharpCode.Decompiler/ILAst/ILAstTypes.cs')
-rw-r--r--ICSharpCode.Decompiler/ILAst/ILAstTypes.cs601
1 files changed, 601 insertions, 0 deletions
diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
new file mode 100644
index 00000000..aab64e6e
--- /dev/null
+++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
@@ -0,0 +1,601 @@
+// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using ICSharpCode.Decompiler;
+using ICSharpCode.Decompiler.Disassembler;
+using ICSharpCode.NRefactory.Utils;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.CSharp;
+using Cecil = Mono.Cecil;
+
+namespace ICSharpCode.Decompiler.ILAst
+{
+ public abstract class ILNode
+ {
+ public IEnumerable<T> GetSelfAndChildrenRecursive<T>(Func<T, bool> predicate = null) where T: ILNode
+ {
+ List<T> result = new List<T>(16);
+ AccumulateSelfAndChildrenRecursive(result, predicate);
+ return result;
+ }
+
+ void AccumulateSelfAndChildrenRecursive<T>(List<T> list, Func<T, bool> predicate) where T:ILNode
+ {
+ // Note: RemoveEndFinally depends on self coming before children
+ T thisAsT = this as T;
+ if (thisAsT != null && (predicate == null || predicate(thisAsT)))
+ list.Add(thisAsT);
+ foreach (ILNode node in GetChildren()) {
+ if (node != null)
+ node.AccumulateSelfAndChildrenRecursive(list, predicate);
+ }
+ }
+
+ public virtual IEnumerable<ILNode> GetChildren()
+ {
+ yield break;
+ }
+
+ public override string ToString()
+ {
+ StringWriter w = new StringWriter();
+ WriteTo(new PlainTextOutput(w));
+ return w.ToString().Replace("\r\n", "; ");
+ }
+
+ public abstract void WriteTo(ITextOutput output);
+ }
+
+ public class ILBlock: ILNode
+ {
+ public ILExpression EntryGoto;
+
+ public List<ILNode> Body;
+
+ public ILBlock(params ILNode[] body)
+ {
+ Body = new List<ILNode>(body);
+ }
+
+ public ILBlock(List<ILNode> body)
+ {
+ Body = body;
+ }
+
+ public override IEnumerable<ILNode> GetChildren()
+ {
+ if (EntryGoto != null)
+ yield return EntryGoto;
+ foreach(ILNode child in Body) {
+ yield return child;
+ }
+ }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ foreach(ILNode child in GetChildren()) {
+ child.WriteTo(output);
+ output.WriteLine();
+ }
+ }
+ }
+
+ public class ILBasicBlock: ILNode
+ {
+ /// <remarks> Body has to start with a label and end with unconditional control flow </remarks>
+ public List<ILNode> Body = new List<ILNode>();
+
+ public override IEnumerable<ILNode> GetChildren()
+ {
+ return Body;
+ }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ foreach(ILNode child in GetChildren()) {
+ child.WriteTo(output);
+ output.WriteLine();
+ }
+ }
+ }
+
+ public class ILLabel: ILNode
+ {
+ public string Name;
+
+ public override void WriteTo(ITextOutput output)
+ {
+ output.WriteDefinition(Name + ":", this);
+ }
+ }
+
+ public class ILTryCatchBlock: ILNode
+ {
+ public class CatchBlock: ILBlock
+ {
+ public TypeReference ExceptionType;
+ public ILVariable ExceptionVariable;
+
+ public override void WriteTo(ITextOutput output)
+ {
+ output.Write("catch ");
+ output.WriteReference(ExceptionType.FullName, ExceptionType);
+ if (ExceptionVariable != null) {
+ output.Write(' ');
+ output.Write(ExceptionVariable.Name);
+ }
+ output.WriteLine(" {");
+ output.Indent();
+ base.WriteTo(output);
+ output.Unindent();
+ output.WriteLine("}");
+ }
+ }
+
+ public ILBlock TryBlock;
+ public List<CatchBlock> CatchBlocks;
+ public ILBlock FinallyBlock;
+ public ILBlock FaultBlock;
+
+ public override IEnumerable<ILNode> GetChildren()
+ {
+ if (TryBlock != null)
+ yield return TryBlock;
+ foreach (var catchBlock in CatchBlocks) {
+ yield return catchBlock;
+ }
+ if (FaultBlock != null)
+ yield return FaultBlock;
+ if (FinallyBlock != null)
+ yield return FinallyBlock;
+ }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ output.WriteLine(".try {");
+ output.Indent();
+ TryBlock.WriteTo(output);
+ output.Unindent();
+ output.WriteLine("}");
+ foreach (CatchBlock block in CatchBlocks) {
+ block.WriteTo(output);
+ }
+ if (FaultBlock != null) {
+ output.WriteLine("fault {");
+ output.Indent();
+ FaultBlock.WriteTo(output);
+ output.Unindent();
+ output.WriteLine("}");
+ }
+ if (FinallyBlock != null) {
+ output.WriteLine("finally {");
+ output.Indent();
+ FinallyBlock.WriteTo(output);
+ output.Unindent();
+ output.WriteLine("}");
+ }
+ }
+ }
+
+ public class ILVariable
+ {
+ public string Name;
+ public bool IsGenerated;
+ public TypeReference Type;
+ public VariableDefinition OriginalVariable;
+ public ParameterDefinition OriginalParameter;
+
+ public bool IsPinned {
+ get { return OriginalVariable != null && OriginalVariable.IsPinned; }
+ }
+
+ public bool IsParameter {
+ get { return OriginalParameter != null; }
+ }
+
+ public override string ToString()
+ {
+ return Name;
+ }
+ }
+
+ public struct ILRange
+ {
+ public readonly int From;
+ public readonly int To; // Exlusive
+
+ public ILRange(int @from, int to)
+ {
+ From = @from;
+ To = to;
+ }
+
+ public override string ToString()
+ {
+ return string.Format("{0:X2}-{1:X2}", From, To);
+ }
+
+ public static List<ILRange> OrderAndJoin(IEnumerable<ILRange> input)
+ {
+ if (input == null)
+ throw new ArgumentNullException("Input is null!");
+
+ List<ILRange> result = new List<ILRange>();
+ foreach(ILRange curr in input.OrderBy(r => r.From)) {
+ if (result.Count > 0) {
+ // Merge consequtive ranges if possible
+ ILRange last = result[result.Count - 1];
+ if (curr.From <= last.To) {
+ result[result.Count - 1] = new ILRange(last.From, Math.Max(last.To, curr.To));
+ continue;
+ }
+ }
+ result.Add(curr);
+ }
+ return result;
+ }
+
+ public static List<ILRange> Invert(IEnumerable<ILRange> input, int codeSize)
+ {
+ if (input == null)
+ throw new ArgumentNullException("Input is null!");
+
+ if (codeSize <= 0)
+ throw new ArgumentException("Code size must be grater than 0");
+
+ List<ILRange> ordered = OrderAndJoin(input);
+ List<ILRange> result = new List<ILRange>(ordered.Count + 1);
+ if (ordered.Count == 0) {
+ result.Add(new ILRange(0, codeSize));
+ } else {
+ // Gap before the first element
+ if (ordered.First().From != 0)
+ result.Add(new ILRange(0, ordered.First().From));
+
+ // Gaps between elements
+ for (int i = 0; i < ordered.Count - 1; i++)
+ result.Add(new ILRange(ordered[i].To, ordered[i + 1].From));
+
+ // Gap after the last element
+ Debug.Assert(ordered.Last().To <= codeSize);
+ if (ordered.Last().To != codeSize)
+ result.Add(new ILRange(ordered.Last().To, codeSize));
+ }
+ return result;
+ }
+ }
+
+ public class ILExpressionPrefix
+ {
+ public readonly ILCode Code;
+ public readonly object Operand;
+
+ public ILExpressionPrefix(ILCode code, object operand = null)
+ {
+ Code = code;
+ Operand = operand;
+ }
+ }
+
+ public class ILExpression : ILNode
+ {
+ public ILCode Code { get; set; }
+ public object Operand { get; set; }
+ public List<ILExpression> Arguments { get; set; }
+ public ILExpressionPrefix[] Prefixes { get; set; }
+ // Mapping to the original instructions (useful for debugging)
+ public List<ILRange> ILRanges { get; set; }
+
+ public TypeReference ExpectedType { get; set; }
+ public TypeReference InferredType { get; set; }
+
+ public static readonly object AnyOperand = new object();
+
+ public ILExpression(ILCode code, object operand, List<ILExpression> args)
+ {
+ if (operand is ILExpression)
+ throw new ArgumentException("operand");
+
+ Code = code;
+ Operand = operand;
+ Arguments = new List<ILExpression>(args);
+ ILRanges = new List<ILRange>(1);
+ }
+
+ public ILExpression(ILCode code, object operand, params ILExpression[] args)
+ {
+ if (operand is ILExpression)
+ throw new ArgumentException("operand");
+
+ Code = code;
+ Operand = operand;
+ Arguments = new List<ILExpression>(args);
+ ILRanges = new List<ILRange>(1);
+ }
+
+ public void AddPrefix(ILExpressionPrefix prefix)
+ {
+ ILExpressionPrefix[] arr = Prefixes;
+ if (arr == null)
+ arr = new ILExpressionPrefix[1];
+ else
+ Array.Resize(ref arr, arr.Length + 1);
+ arr[arr.Length - 1] = prefix;
+ Prefixes = arr;
+ }
+
+ public ILExpressionPrefix GetPrefix(ILCode code)
+ {
+ var prefixes = Prefixes;
+ if (prefixes != null) {
+ foreach (ILExpressionPrefix p in prefixes) {
+ if (p.Code == code)
+ return p;
+ }
+ }
+ return null;
+ }
+
+ public override IEnumerable<ILNode> GetChildren()
+ {
+ return Arguments;
+ }
+
+ public bool IsBranch()
+ {
+ return Operand is ILLabel || Operand is ILLabel[];
+ }
+
+ public IEnumerable<ILLabel> GetBranchTargets()
+ {
+ if (Operand is ILLabel) {
+ return new ILLabel[] { (ILLabel)Operand };
+ } else if (Operand is ILLabel[]) {
+ return (ILLabel[])Operand;
+ } else {
+ return new ILLabel[] { };
+ }
+ }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) {
+ if (Code == ILCode.Stloc && InferredType == null) {
+ output.Write(((ILVariable)Operand).Name);
+ output.Write(" = ");
+ Arguments.First().WriteTo(output);
+ return;
+ } else if (Code == ILCode.Ldloc) {
+ output.Write(((ILVariable)Operand).Name);
+ if (InferredType != null) {
+ output.Write(':');
+ InferredType.WriteTo(output, ILNameSyntax.ShortTypeName);
+ if (ExpectedType != null && ExpectedType.FullName != InferredType.FullName) {
+ output.Write("[exp:");
+ ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
+ output.Write(']');
+ }
+ }
+ return;
+ }
+ }
+
+ if (Prefixes != null) {
+ foreach (var prefix in Prefixes) {
+ output.Write(prefix.Code.GetName());
+ output.Write(". ");
+ }
+ }
+
+ output.Write(Code.GetName());
+ if (InferredType != null) {
+ output.Write(':');
+ InferredType.WriteTo(output, ILNameSyntax.ShortTypeName);
+ if (ExpectedType != null && ExpectedType.FullName != InferredType.FullName) {
+ output.Write("[exp:");
+ ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
+ output.Write(']');
+ }
+ } else if (ExpectedType != null) {
+ output.Write("[exp:");
+ ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
+ output.Write(']');
+ }
+ output.Write('(');
+ bool first = true;
+ if (Operand != null) {
+ if (Operand is ILLabel) {
+ output.WriteReference(((ILLabel)Operand).Name, Operand);
+ } else if (Operand is ILLabel[]) {
+ ILLabel[] labels = (ILLabel[])Operand;
+ for (int i = 0; i < labels.Length; i++) {
+ if (i > 0)
+ output.Write(", ");
+ output.WriteReference(labels[i].Name, labels[i]);
+ }
+ } else if (Operand is MethodReference) {
+ MethodReference method = (MethodReference)Operand;
+ if (method.DeclaringType != null) {
+ method.DeclaringType.WriteTo(output, ILNameSyntax.ShortTypeName);
+ output.Write("::");
+ }
+ output.WriteReference(method.Name, method);
+ } else if (Operand is FieldReference) {
+ FieldReference field = (FieldReference)Operand;
+ field.DeclaringType.WriteTo(output, ILNameSyntax.ShortTypeName);
+ output.Write("::");
+ output.WriteReference(field.Name, field);
+ } else {
+ DisassemblerHelpers.WriteOperand(output, Operand);
+ }
+ first = false;
+ }
+ foreach (ILExpression arg in Arguments) {
+ if (!first) output.Write(", ");
+ arg.WriteTo(output);
+ first = false;
+ }
+ output.Write(')');
+ }
+ }
+
+ public class ILWhileLoop : ILNode
+ {
+ public ILExpression Condition;
+ public ILBlock BodyBlock;
+
+ public override IEnumerable<ILNode> GetChildren()
+ {
+ if (Condition != null)
+ yield return Condition;
+ if (BodyBlock != null)
+ yield return BodyBlock;
+ }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ output.WriteLine("");
+ output.Write("loop (");
+ if (Condition != null)
+ Condition.WriteTo(output);
+ output.WriteLine(") {");
+ output.Indent();
+ BodyBlock.WriteTo(output);
+ output.Unindent();
+ output.WriteLine("}");
+ }
+ }
+
+ public class ILCondition : ILNode
+ {
+ public ILExpression Condition;
+ public ILBlock TrueBlock; // Branch was taken
+ public ILBlock FalseBlock; // Fall-though
+
+ public override IEnumerable<ILNode> GetChildren()
+ {
+ if (Condition != null)
+ yield return Condition;
+ if (TrueBlock != null)
+ yield return TrueBlock;
+ if (FalseBlock != null)
+ yield return FalseBlock;
+ }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ output.Write("if (");
+ Condition.WriteTo(output);
+ output.WriteLine(") {");
+ output.Indent();
+ TrueBlock.WriteTo(output);
+ output.Unindent();
+ output.Write("}");
+ if (FalseBlock != null) {
+ output.WriteLine(" else {");
+ output.Indent();
+ FalseBlock.WriteTo(output);
+ output.Unindent();
+ output.WriteLine("}");
+ }
+ }
+ }
+
+ public class ILSwitch: ILNode
+ {
+ public class CaseBlock: ILBlock
+ {
+ public List<int> Values; // null for the default case
+
+ public override void WriteTo(ITextOutput output)
+ {
+ if (Values != null) {
+ foreach (int i in Values) {
+ output.WriteLine("case {0}:", i);
+ }
+ } else {
+ output.WriteLine("default:");
+ }
+ output.Indent();
+ base.WriteTo(output);
+ output.Unindent();
+ }
+ }
+
+ public ILExpression Condition;
+ public List<CaseBlock> CaseBlocks = new List<CaseBlock>();
+
+ public override IEnumerable<ILNode> GetChildren()
+ {
+ if (Condition != null)
+ yield return Condition;
+ foreach (ILBlock caseBlock in CaseBlocks) {
+ yield return caseBlock;
+ }
+ }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ output.Write("switch (");
+ Condition.WriteTo(output);
+ output.WriteLine(") {");
+ output.Indent();
+ foreach (CaseBlock caseBlock in CaseBlocks) {
+ caseBlock.WriteTo(output);
+ }
+ output.Unindent();
+ output.WriteLine("}");
+ }
+ }
+
+ public class ILFixedStatement : ILNode
+ {
+ public List<ILExpression> Initializers = new List<ILExpression>();
+ public ILBlock BodyBlock;
+
+ public override IEnumerable<ILNode> GetChildren()
+ {
+ foreach (ILExpression initializer in Initializers)
+ yield return initializer;
+ if (BodyBlock != null)
+ yield return BodyBlock;
+ }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ output.Write("fixed (");
+ for (int i = 0; i < Initializers.Count; i++) {
+ if (i > 0)
+ output.Write(", ");
+ Initializers[i].WriteTo(output);
+ }
+ output.WriteLine(") {");
+ output.Indent();
+ BodyBlock.WriteTo(output);
+ output.Unindent();
+ output.WriteLine("}");
+ }
+ }
+} \ No newline at end of file