Browse Source

Merge branch 'master' of github.com:icsharpcode/ILSpy

pull/1/head
Daniel Grunwald 15 years ago
parent
commit
05b17578dd
  1. 80
      ICSharpCode.Decompiler/DominanceLoopDetector.cs
  2. 16
      ICSharpCode.Decompiler/FlowAnalysis/ControlFlowEdge.cs
  3. 31
      ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs
  4. 15
      ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs
  5. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  6. 7
      ILSpy/Decompiler/CSharpLanguage.cs
  7. 45
      ILSpy/Disassembler/ILLanguage.cs
  8. 5
      ILSpy/MainWindow.xaml.cs

80
ICSharpCode.Decompiler/DominanceLoopDetector.cs

@ -0,0 +1,80 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.Decompiler.FlowAnalysis;
namespace ICSharpCode.Decompiler
{
/// <summary>
/// Description of DominanceLoopDetector.
/// </summary>
public class DominanceLoopDetector
{
public static ControlStructure DetectLoops(ControlFlowGraph g)
{
ControlStructure root = new ControlStructure(
new HashSet<ControlFlowNode>(g.Nodes),
g.EntryPoint
);
DetectLoops(g, root);
g.ResetVisited();
return root;
}
static void DetectLoops(ControlFlowGraph g, ControlStructure current)
{
g.ResetVisited();
FindLoops(current, current.EntryPoint);
foreach (ControlStructure loop in current.Children)
DetectLoops(g, loop);
}
static void FindLoops(ControlStructure current, ControlFlowNode node)
{
if (node.Visited)
return;
node.Visited = true;
if (current.Nodes.Contains(node)
&& node.DominanceFrontier.Contains(node)
&& node != current.EntryPoint)
{
HashSet<ControlFlowNode> loopContents = new HashSet<ControlFlowNode>();
FindLoopContents(current, loopContents, node, node);
current.Nodes.ExceptWith(loopContents);
current.Children.Add(new ControlStructure(loopContents, node));
}
foreach (var edge in node.Outgoing) {
FindLoops(current, edge.Target);
}
}
static void FindLoopContents(ControlStructure current, HashSet<ControlFlowNode> loopContents, ControlFlowNode loopHead, ControlFlowNode node)
{
if (current.Nodes.Contains(node) && loopHead.Dominates(node) && loopContents.Add(node)) {
foreach (var edge in node.Incoming) {
FindLoopContents(current, loopContents, loopHead, edge.Source);
}
}
}
}
public class ControlStructure
{
public List<ControlStructure> Children = new List<ControlStructure>();
public HashSet<ControlFlowNode> Nodes;
public ControlFlowNode EntryPoint;
public ControlStructure(HashSet<ControlFlowNode> nodes, ControlFlowNode entryPoint)
{
this.Nodes = nodes;
this.EntryPoint = entryPoint;
}
}
}

16
ICSharpCode.Decompiler/FlowAnalysis/ControlFlowEdge.cs

@ -23,9 +23,23 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
public enum JumpType
{
Normal,
/// <summary>
/// Jump to exception handler (an exception occurred)
/// </summary>
JumpToExceptionHandler,
/// <summary>
/// Jump from try block to leave target:
/// This is not a real jump, as the finally handler is executed first!
/// </summary>
LeaveTry,
MutualProtection
/// <summary>
/// Jump from one catch block to its sibling
/// </summary>
MutualProtection,
/// <summary>
/// non-determistic jump at end finally (to any of the potential leave targets)
/// </summary>
EndFinally
}
public sealed class ControlFlowEdge

31
ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs

@ -32,14 +32,14 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
return new ControlFlowGraphBuilder(methodBody).Build();
}
bool copyFinallyBlocks = false;
MethodBody methodBody;
int[] offsets; // array index = instruction index; value = IL offset
bool[] hasIncomingJumps; // array index = instruction index
List<ControlFlowNode> nodes = new List<ControlFlowNode>();
ControlFlowNode entryPoint;
ControlFlowNode regularExit ;
ControlFlowNode regularExit;
ControlFlowNode exceptionalExit;
//Stack<> activeExceptionHandlers = new Stack<ExceptionHandler>();
private ControlFlowGraphBuilder(MethodBody methodBody)
{
@ -69,7 +69,10 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
CreateNodes();
CreateRegularControlFlow();
CreateExceptionalControlFlow();
CopyFinallyBlocksIntoLeaveEdges();
if (copyFinallyBlocks)
CopyFinallyBlocksIntoLeaveEdges();
else
TransformLeaveEdges();
return new ControlFlowGraph(nodes.ToArray());
}
@ -242,6 +245,28 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
}
}
void TransformLeaveEdges()
{
for (int i = nodes.Count - 1; i >= 0; i--) {
ControlFlowNode node = nodes[i];
if (node.End != null && node.Outgoing.Count == 1 && node.Outgoing[0].Type == JumpType.LeaveTry) {
Debug.Assert(node.End.OpCode == OpCodes.Leave);
ControlFlowNode target = node.Outgoing[0].Target;
// remove the edge
target.Incoming.Remove(node.Outgoing[0]);
node.Outgoing.Clear();
ControlFlowNode handler = FindInnermostExceptionHandler(node.End.Offset);
Debug.Assert(handler.NodeType == ControlFlowNodeType.FinallyOrFaultHandler);
CreateEdge(node, handler, JumpType.Normal);
CreateEdge(handler.EndFinallyOrFaultNode, target, JumpType.EndFinally);
}
}
}
/// <summary>
/// Creates a copy of all nodes pointing to 'end' and replaces those references with references to 'newEnd'.
/// Nodes pointing to the copied node are copied recursively to update those references, too.

15
ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs

@ -174,11 +174,26 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
// writer.WriteLine();
// writer.Write("ImmediateDominator: #{0}", ImmediateDominator.BlockIndex);
// }
if (DominanceFrontier != null && DominanceFrontier.Any()) {
writer.WriteLine();
writer.Write("DominanceFrontier: " + string.Join(",", DominanceFrontier.OrderBy(d => d.BlockIndex).Select(d => d.BlockIndex.ToString())));
}
foreach (Instruction inst in this.Instructions) {
writer.WriteLine();
inst.WriteTo(writer);
}
return writer.ToString();
}
public bool Dominates(ControlFlowNode node)
{
ControlFlowNode tmp = node;
while (tmp != null) {
if (tmp == this)
return true;
tmp = tmp.ImmediateDominator;
}
return false;
}
}
}

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -50,6 +50,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CecilExtensions.cs" />
<Compile Include="DominanceLoopDetector.cs" />
<Compile Include="FlowAnalysis\ControlFlowEdge.cs" />
<Compile Include="FlowAnalysis\ControlFlowGraph.cs" />
<Compile Include="FlowAnalysis\ControlFlowGraphBuilder.cs" />

7
ILSpy/Decompiler/CSharpLanguage.cs

@ -17,7 +17,11 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.FlowAnalysis;
using Mono.Cecil;
using Mono.Cecil.Rocks;
namespace ICSharpCode.ILSpy.Decompiler
{
@ -30,8 +34,9 @@ namespace ICSharpCode.ILSpy.Decompiler
get { return "C#"; }
}
public override void Decompile(MethodDefinition methodDefinition, ITextOutput output)
public override void Decompile(MethodDefinition method, ITextOutput output)
{
throw new NotImplementedException();
}
}
}

45
ILSpy/Disassembler/ILLanguage.cs

@ -17,7 +17,11 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.FlowAnalysis;
using Mono.Cecil;
using Mono.Cecil.Rocks;
namespace ICSharpCode.ILSpy.Disassembler
{
@ -27,6 +31,8 @@ namespace ICSharpCode.ILSpy.Disassembler
get { return "IL"; }
}
bool detectControlStructure = true;
public override void Decompile(MethodDefinition method, ITextOutput output)
{
output.WriteComment("// Method begins at RVA 0x{0:x4}", method.RVA);
@ -53,15 +59,44 @@ namespace ICSharpCode.ILSpy.Disassembler
output.WriteLine(")");
}
foreach (var inst in method.Body.Instructions) {
inst.WriteTo(output);
if (detectControlStructure) {
method.Body.SimplifyMacros();
var cfg = ControlFlowGraphBuilder.Build(method.Body);
cfg.ComputeDominance();
cfg.ComputeDominanceFrontier();
var s = DominanceLoopDetector.DetectLoops(cfg);
WriteStructure(output, s);
} else {
foreach (var inst in method.Body.Instructions) {
inst.WriteTo(output);
output.WriteLine();
}
output.WriteLine();
foreach (var eh in method.Body.ExceptionHandlers) {
eh.WriteTo(output);
output.WriteLine();
}
}
}
void WriteStructure(ITextOutput output, ControlStructure s)
{
output.WriteComment("// loop start");
output.WriteLine();
foreach (var eh in method.Body.ExceptionHandlers) {
eh.WriteTo(output);
output.WriteLine();
output.Indent();
foreach (var node in s.Nodes.Concat(s.Children.Select(c => c.EntryPoint)).OrderBy(n => n.BlockIndex)) {
if (s.Nodes.Contains(node)) {
foreach (var inst in node.Instructions) {
inst.WriteTo(output);
output.WriteLine();
}
} else {
WriteStructure(output, s.Children.Single(c => c.EntryPoint == node));
}
}
output.Unindent();
output.WriteComment("// loop end");
output.WriteLine();
}
}
}

5
ILSpy/MainWindow.xaml.cs

@ -125,7 +125,10 @@ namespace ICSharpCode.ILSpy
MethodTreeNode node = treeView.SelectedItem as MethodTreeNode;
if (node != null && node.MethodDefinition.HasBody) {
node.MethodDefinition.Body.SimplifyMacros();
ShowGraph(node.MethodDefinition.Name + "-cfg", ControlFlowGraphBuilder.Build(node.MethodDefinition.Body).ExportGraph());
var cfg = ControlFlowGraphBuilder.Build(node.MethodDefinition.Body);
cfg.ComputeDominance();
cfg.ComputeDominanceFrontier();
ShowGraph(node.MethodDefinition.Name + "-cfg", cfg.ExportGraph());
}
}

Loading…
Cancel
Save