PageRenderTime 72ms CodeModel.GetById 14ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 1ms

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