diff options
Diffstat (limited to 'ICSharpCode.Decompiler/ILAst/ILAstTypes.cs')
-rw-r--r-- | ICSharpCode.Decompiler/ILAst/ILAstTypes.cs | 601 |
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 |