|
|
@ -23,7 +23,7 @@ namespace Decompiler.ControlFlow |
|
|
|
graph = BuildGraph(block.Body, block.EntryPoint); |
|
|
|
graph = BuildGraph(block.Body, block.EntryPoint); |
|
|
|
graph.ComputeDominance(); |
|
|
|
graph.ComputeDominance(); |
|
|
|
graph.ComputeDominanceFrontier(); |
|
|
|
graph.ComputeDominanceFrontier(); |
|
|
|
block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint); |
|
|
|
block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, false); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().Where(b => !(b is ILMoveableBlock)).ToList()) { |
|
|
|
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().Where(b => !(b is ILMoveableBlock)).ToList()) { |
|
|
@ -34,7 +34,7 @@ namespace Decompiler.ControlFlow |
|
|
|
block.Body = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint); |
|
|
|
block.Body = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
OrderNodes(method); |
|
|
|
// OrderNodes(method);
|
|
|
|
FlattenNestedMovableBlocks(method); |
|
|
|
FlattenNestedMovableBlocks(method); |
|
|
|
SimpleGotoRemoval(method); |
|
|
|
SimpleGotoRemoval(method); |
|
|
|
RemoveDeadLabels(method); |
|
|
|
RemoveDeadLabels(method); |
|
|
@ -155,7 +155,7 @@ namespace Decompiler.ControlFlow |
|
|
|
return new ControlFlowGraph(cfNodes.ToArray()); |
|
|
|
return new ControlFlowGraph(cfNodes.ToArray()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
List<ILNode> FindLoops(HashSet<ControlFlowNode> nodes, ControlFlowNode entryPoint) |
|
|
|
List<ILNode> FindLoops(HashSet<ControlFlowNode> nodes, ControlFlowNode entryPoint, bool excludeEntryPoint) |
|
|
|
{ |
|
|
|
{ |
|
|
|
List<ILNode> result = new List<ILNode>(); |
|
|
|
List<ILNode> result = new List<ILNode>(); |
|
|
|
|
|
|
|
|
|
|
@ -166,7 +166,7 @@ namespace Decompiler.ControlFlow |
|
|
|
|
|
|
|
|
|
|
|
if (nodes.Contains(node) |
|
|
|
if (nodes.Contains(node) |
|
|
|
&& node.DominanceFrontier.Contains(node) |
|
|
|
&& node.DominanceFrontier.Contains(node) |
|
|
|
&& node != entryPoint) |
|
|
|
&& (node != entryPoint || !excludeEntryPoint)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
HashSet<ControlFlowNode> loopContents = new HashSet<ControlFlowNode>(); |
|
|
|
HashSet<ControlFlowNode> loopContents = new HashSet<ControlFlowNode>(); |
|
|
|
FindLoopContents(nodes, loopContents, node, node); |
|
|
|
FindLoopContents(nodes, loopContents, node, node); |
|
|
@ -175,7 +175,7 @@ namespace Decompiler.ControlFlow |
|
|
|
nodes.ExceptWith(loopContents); |
|
|
|
nodes.ExceptWith(loopContents); |
|
|
|
ILLabel entryLabel = new ILLabel() { Name = "Loop_" + (nextBlockIndex++) }; |
|
|
|
ILLabel entryLabel = new ILLabel() { Name = "Loop_" + (nextBlockIndex++) }; |
|
|
|
((ILBlock)node.UserData).Body.Insert(0, entryLabel); |
|
|
|
((ILBlock)node.UserData).Body.Insert(0, entryLabel); |
|
|
|
result.Add(new ILLoop() { ContentBlock = new ILBlock(FindLoops(loopContents, node)) { EntryPoint = entryLabel } }); |
|
|
|
result.Add(new ILLoop() { ContentBlock = new ILBlock(FindLoops(loopContents, node, true)) { EntryPoint = entryLabel } }); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Using the dominator tree should ensure we find the the widest loop first
|
|
|
|
// Using the dominator tree should ensure we find the the widest loop first
|
|
|
@ -210,58 +210,66 @@ namespace Decompiler.ControlFlow |
|
|
|
while(agenda.Count > 0) { |
|
|
|
while(agenda.Count > 0) { |
|
|
|
ControlFlowNode node = agenda.Dequeue(); |
|
|
|
ControlFlowNode node = agenda.Dequeue(); |
|
|
|
|
|
|
|
|
|
|
|
ILMoveableBlock block = node.UserData as ILMoveableBlock; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Find a block that represents a simple condition
|
|
|
|
// Find a block that represents a simple condition
|
|
|
|
if (nodes.Contains(node) && block != null && block.Body.Count == 3) { |
|
|
|
if (nodes.Contains(node)) { |
|
|
|
|
|
|
|
|
|
|
|
ILLabel label = block.Body[0] as ILLabel; |
|
|
|
ILMoveableBlock block = node.UserData as ILMoveableBlock; |
|
|
|
ILExpression condBranch = block.Body[1] as ILExpression; |
|
|
|
|
|
|
|
ILExpression statBranch = block.Body[2] as ILExpression; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (label != null && |
|
|
|
if (block != null && block.Body.Count == 3) { |
|
|
|
condBranch != null && condBranch.Operand is ILLabel && condBranch.Arguments.Count > 0 && |
|
|
|
ILLabel label = block.Body[0] as ILLabel; |
|
|
|
statBranch != null && statBranch.Operand is ILLabel && statBranch.Arguments.Count == 0) |
|
|
|
ILExpression condBranch = block.Body[1] as ILExpression; |
|
|
|
{ |
|
|
|
ILExpression statBranch = block.Body[2] as ILExpression; |
|
|
|
ControlFlowNode condTarget; |
|
|
|
|
|
|
|
ControlFlowNode statTarget; |
|
|
|
if (label != null && |
|
|
|
if (labelToCfNode.TryGetValue((ILLabel)condBranch.Operand, out condTarget) && |
|
|
|
condBranch != null && condBranch.Operand is ILLabel && condBranch.Arguments.Count > 0 && |
|
|
|
labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget)) |
|
|
|
statBranch != null && statBranch.Operand is ILLabel && statBranch.Arguments.Count == 0) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ILCondition condition = new ILCondition() { |
|
|
|
ControlFlowNode condTarget; |
|
|
|
Condition = condBranch, |
|
|
|
ControlFlowNode statTarget; |
|
|
|
TrueBlock = new ILBlock() { EntryPoint = (ILLabel)condBranch.Operand }, |
|
|
|
if (labelToCfNode.TryGetValue((ILLabel)condBranch.Operand, out condTarget) && |
|
|
|
FalseBlock = new ILBlock() { EntryPoint = (ILLabel)statBranch.Operand } |
|
|
|
labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget)) |
|
|
|
}; |
|
|
|
{ |
|
|
|
|
|
|
|
ILCondition condition = new ILCondition() { |
|
|
|
// The label will not be used - kill it
|
|
|
|
Condition = condBranch, |
|
|
|
condBranch.Operand = null; |
|
|
|
TrueBlock = new ILBlock() { EntryPoint = (ILLabel)condBranch.Operand }, |
|
|
|
|
|
|
|
FalseBlock = new ILBlock() { EntryPoint = (ILLabel)statBranch.Operand } |
|
|
|
// Replace the two branches with a conditional structure
|
|
|
|
}; |
|
|
|
block.Body.Remove(condBranch); |
|
|
|
|
|
|
|
block.Body.Remove(statBranch); |
|
|
|
// The label will not be used - kill it
|
|
|
|
block.Body.Add(condition); |
|
|
|
condBranch.Operand = null; |
|
|
|
result.Add(block); |
|
|
|
|
|
|
|
|
|
|
|
// Replace the two branches with a conditional structure
|
|
|
|
// Pull in the conditional code
|
|
|
|
block.Body.Remove(condBranch); |
|
|
|
HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>(); |
|
|
|
block.Body.Remove(statBranch); |
|
|
|
frontiers.UnionWith(condTarget.DominanceFrontier); |
|
|
|
block.Body.Add(condition); |
|
|
|
frontiers.UnionWith(statTarget.DominanceFrontier); |
|
|
|
result.Add(block); |
|
|
|
|
|
|
|
|
|
|
|
if (!frontiers.Contains(condTarget)) { |
|
|
|
// Pull in the conditional code
|
|
|
|
HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget); |
|
|
|
HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>(); |
|
|
|
nodes.ExceptWith(content); |
|
|
|
frontiers.UnionWith(condTarget.DominanceFrontier); |
|
|
|
condition.TrueBlock.Body.AddRange(FindConditions(content, condTarget)); |
|
|
|
frontiers.UnionWith(statTarget.DominanceFrontier); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!frontiers.Contains(condTarget)) { |
|
|
|
|
|
|
|
HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget); |
|
|
|
|
|
|
|
nodes.ExceptWith(content); |
|
|
|
|
|
|
|
condition.TrueBlock.Body.AddRange(FindConditions(content, condTarget)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!frontiers.Contains(statTarget)) { |
|
|
|
|
|
|
|
HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, statTarget); |
|
|
|
|
|
|
|
nodes.ExceptWith(content); |
|
|
|
|
|
|
|
condition.FalseBlock.Body.AddRange(FindConditions(content, statTarget)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nodes.Remove(node); |
|
|
|
} |
|
|
|
} |
|
|
|
if (!frontiers.Contains(statTarget)) { |
|
|
|
|
|
|
|
HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, statTarget); |
|
|
|
|
|
|
|
nodes.ExceptWith(content); |
|
|
|
|
|
|
|
condition.FalseBlock.Body.AddRange(FindConditions(content, statTarget)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nodes.Remove(node); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add the node now so that we have good ordering
|
|
|
|
|
|
|
|
if (nodes.Contains(node)) { |
|
|
|
|
|
|
|
result.Add((ILNode)node.UserData); |
|
|
|
|
|
|
|
nodes.Remove(node); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Using the dominator tree should ensure we find the the widest loop first
|
|
|
|
// Using the dominator tree should ensure we find the the widest loop first
|
|
|
|