PageRenderTime 37ms CodeModel.GetById 7ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/ICSharpCode.Decompiler/FlowAnalysis/SsaForm.cs

http://github.com/icsharpcode/ILSpy
C# | 162 lines | 127 code | 14 blank | 21 comment | 28 complexity | b78f5fdd757310e6e1441df3a3059b3c MD5 | raw file
  1// Copyright (c) 2010 Daniel Grunwald
  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.Collections.ObjectModel;
 22using System.Diagnostics;
 23using System.Linq;
 24
 25using ICSharpCode.NRefactory.Utils;
 26using Mono.Cecil;
 27using Mono.Cecil.Cil;
 28
 29namespace ICSharpCode.Decompiler.FlowAnalysis
 30{
 31	/// <summary>
 32	/// Represents a graph of SsaBlocks.
 33	/// </summary>
 34	public sealed class SsaForm
 35	{
 36		readonly SsaVariable[] parameters;
 37		readonly SsaVariable[] locals;
 38		public readonly ReadOnlyCollection<SsaVariable> OriginalVariables;
 39		public readonly ReadOnlyCollection<SsaBlock> Blocks;
 40		readonly bool methodHasThis;
 41		
 42		public SsaBlock EntryPoint {
 43			get { return this.Blocks[0]; }
 44		}
 45		
 46		public SsaBlock RegularExit {
 47			get { return this.Blocks[1]; }
 48		}
 49		
 50		public SsaBlock ExceptionalExit {
 51			get { return this.Blocks[2]; }
 52		}
 53		
 54		internal SsaForm(SsaBlock[] blocks, SsaVariable[] parameters, SsaVariable[] locals, SsaVariable[] stackLocations, bool methodHasThis)
 55		{
 56			this.parameters = parameters;
 57			this.locals = locals;
 58			this.Blocks = new ReadOnlyCollection<SsaBlock>(blocks);
 59			this.OriginalVariables = new ReadOnlyCollection<SsaVariable>(parameters.Concat(locals).Concat(stackLocations).ToList());
 60			this.methodHasThis = methodHasThis;
 61			
 62			Debug.Assert(EntryPoint.NodeType == ControlFlowNodeType.EntryPoint);
 63			Debug.Assert(RegularExit.NodeType == ControlFlowNodeType.RegularExit);
 64			Debug.Assert(ExceptionalExit.NodeType == ControlFlowNodeType.ExceptionalExit);
 65			for (int i = 0; i < this.OriginalVariables.Count; i++) {
 66				this.OriginalVariables[i].OriginalVariableIndex = i;
 67			}
 68		}
 69		
 70		public GraphVizGraph ExportBlockGraph(Func<SsaBlock, string> labelProvider = null)
 71		{
 72			if (labelProvider == null)
 73				labelProvider = b => b.ToString();
 74			GraphVizGraph graph = new GraphVizGraph();
 75			foreach (SsaBlock block in this.Blocks) {
 76				graph.AddNode(new GraphVizNode(block.BlockIndex) { label = labelProvider(block), shape = "box" });
 77			}
 78			foreach (SsaBlock block in this.Blocks) {
 79				foreach (SsaBlock s in block.Successors) {
 80					graph.AddEdge(new GraphVizEdge(block.BlockIndex, s.BlockIndex));
 81				}
 82			}
 83			return graph;
 84		}
 85		
 86		public GraphVizGraph ExportVariableGraph(Func<SsaVariable, string> labelProvider = null)
 87		{
 88			if (labelProvider == null)
 89				labelProvider = v => v.ToString();
 90			GraphVizGraph graph = new GraphVizGraph();
 91			foreach (SsaVariable v in this.AllVariables) {
 92				graph.AddNode(new GraphVizNode(v.Name) { label = labelProvider(v) });
 93			}
 94			int instructionIndex = 0;
 95			foreach (SsaBlock block in this.Blocks) {
 96				foreach (SsaInstruction inst in block.Instructions) {
 97					if (inst.Operands.Length == 0 && inst.Target == null)
 98						continue;
 99					string id = "instruction" + (++instructionIndex);
100					graph.AddNode(new GraphVizNode(id) { label = inst.ToString(), shape = "box" });
101					foreach (SsaVariable op in inst.Operands)
102						graph.AddEdge(new GraphVizEdge(op.Name, id));
103					if (inst.Target != null)
104						graph.AddEdge(new GraphVizEdge(id, inst.Target.Name));
105				}
106			}
107			return graph;
108		}
109		
110		public SsaVariable GetOriginalVariable(ParameterReference parameter)
111		{
112			if (methodHasThis)
113				return parameters[parameter.Index + 1];
114			else
115				return parameters[parameter.Index];
116		}
117		
118		public SsaVariable GetOriginalVariable(VariableReference variable)
119		{
120			return locals[variable.Index];
121		}
122		
123		#region ComputeVariableUsage
124		public void ComputeVariableUsage()
125		{
126			// clear data from previous runs
127			foreach (SsaBlock block in this.Blocks) {
128				foreach (SsaInstruction inst in block.Instructions) {
129					foreach (SsaVariable v in inst.Operands) {
130						if (v.Usage != null)
131							v.Usage.Clear();
132					}
133					if (inst.Target != null && inst.Target.Usage != null)
134						inst.Target.Usage.Clear();
135				}
136			}
137			foreach (SsaBlock block in this.Blocks) {
138				foreach (SsaInstruction inst in block.Instructions) {
139					foreach (SsaVariable v in inst.Operands) {
140						if (v.Usage == null)
141							v.Usage = new List<SsaInstruction>();
142						v.Usage.Add(inst);
143					}
144					if (inst.Target != null && inst.Target.Usage == null)
145						inst.Target.Usage = new List<SsaInstruction>();
146				}
147			}
148		}
149		#endregion
150		
151		public IEnumerable<SsaVariable> AllVariables {
152			get {
153				return (
154					from block in this.Blocks
155					from instruction in block.Instructions
156					where instruction.Target != null
157					select instruction.Target
158				).Distinct();
159			}
160		}
161	}
162}