Browse Source

Duplicate return statements

pull/70/head
David Srbecký 15 years ago
parent
commit
effe892409
  1. 26
      ICSharpCode.Decompiler/ILAst/GotoRemoval.cs
  2. 140
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

26
ICSharpCode.Decompiler/ILAst/GotoRemoval.cs

@ -12,7 +12,7 @@ namespace Decompiler
Dictionary<ILNode, ILNode> parent = new Dictionary<ILNode, ILNode>(); Dictionary<ILNode, ILNode> parent = new Dictionary<ILNode, ILNode>();
Dictionary<ILNode, ILNode> nextSibling = new Dictionary<ILNode, ILNode>(); Dictionary<ILNode, ILNode> nextSibling = new Dictionary<ILNode, ILNode>();
public bool RemoveGotos(ILBlock method) public void RemoveGotos(ILBlock method)
{ {
// Build the navigation data // Build the navigation data
parent[method] = null; parent[method] = null;
@ -30,33 +30,33 @@ namespace Decompiler
} }
// Simplify gotos // Simplify gotos
bool modified = false;
foreach (ILExpression gotoExpr in method.GetSelfAndChildrenRecursive<ILExpression>().Where(e => e.Code == ILCode.Br || e.Code == ILCode.Leave)) { foreach (ILExpression gotoExpr in method.GetSelfAndChildrenRecursive<ILExpression>().Where(e => e.Code == ILCode.Br || e.Code == ILCode.Leave)) {
modified |= TrySimplifyGoto(gotoExpr); TrySimplifyGoto(gotoExpr);
} }
// Remove dead lables and nops // Remove dead lables and nops
HashSet<ILLabel> liveLabels = new HashSet<ILLabel>(method.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.GetBranchTargets())); RemoveDeadLabels(method);
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
int oldBodyCount = block.Body.Count;
block.Body = block.Body.Where(n => !n.Matches(ILCode.Nop) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList();
modified |= block.Body.Count < oldBodyCount;
}
// Remove redundant continue // Remove redundant continue
foreach(ILWhileLoop loop in method.GetSelfAndChildrenRecursive<ILWhileLoop>()) { foreach(ILWhileLoop loop in method.GetSelfAndChildrenRecursive<ILWhileLoop>()) {
var body = loop.BodyBlock.Body; var body = loop.BodyBlock.Body;
if (body.Count > 0 && body.Last().Matches(ILCode.LoopContinue)) { if (body.Count > 0 && body.Last().Match(ILCode.LoopContinue)) {
body.RemoveAt(body.Count - 1); body.RemoveAt(body.Count - 1);
} }
} }
// Remove redundant return // Remove redundant return
if (method.Body.Count > 0 && method.Body.Last().Matches(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0) { if (method.Body.Count > 0 && method.Body.Last().Match(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0) {
method.Body.RemoveAt(method.Body.Count - 1); method.Body.RemoveAt(method.Body.Count - 1);
} }
}
return modified;
public static void RemoveDeadLabels(ILNode method)
{
HashSet<ILLabel> liveLabels = new HashSet<ILLabel>(method.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.GetBranchTargets()));
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
block.Body = block.Body.Where(n => !n.Match(ILCode.Nop) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList();
}
} }
bool TrySimplifyGoto(ILExpression gotoExpr) bool TrySimplifyGoto(ILExpression gotoExpr)

140
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -17,6 +17,7 @@ namespace Decompiler.ControlFlow
FindConditions, FindConditions,
FlattenNestedMovableBlocks, FlattenNestedMovableBlocks,
GotoRemoval, GotoRemoval,
DuplicateReturns,
HandleArrayInitializers, HandleArrayInitializers,
TypeInference, TypeInference,
None None
@ -62,17 +63,16 @@ 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);
} }
// AnalyseLabels(method);
// foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
// ReturnOptimizations(block);
// }
if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return; if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return;
FlattenBasicBlocks(method); FlattenBasicBlocks(method);
if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval) return; if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval) return;
new GotoRemoval().RemoveGotos(method); new GotoRemoval().RemoveGotos(method);
if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns) return;
DuplicateReturnStatements(method);
GotoRemoval.RemoveDeadLabels(method);
if (abortBeforeStep == ILAstOptimizationStep.HandleArrayInitializers) return; if (abortBeforeStep == ILAstOptimizationStep.HandleArrayInitializers) return;
ArrayInitializers.Transform(method); ArrayInitializers.Transform(method);
@ -325,92 +325,48 @@ namespace Decompiler.ControlFlow
return false; return false;
} }
void ReturnOptimizations(ILBlock block) void DuplicateReturnStatements(ILBlock method)
{
bool modified;
do {
modified = false;
for (int i = 0; i < block.Body.Count;) {
ILBasicBlock bb = block.Body[i] as ILBasicBlock;
// TODO: Isn't basicblock?
if (bb != null && TryDuplicateFollowingReturn(block.Body, bb)) {
modified = true;
continue;
}
i++;
}
} while(modified);
}
bool TryDuplicateFollowingReturn(List<ILNode> scope, ILBasicBlock head)
{ {
bool modified = false; Dictionary<ILLabel, ILNode> nextSibling = new Dictionary<ILLabel, ILNode>();
if (head.FallthoughGoto != null) {
ILLabel fallLabel = (ILLabel)head.FallthoughGoto.Operand; // Build navigation data
ILLabel dupLabel = null; foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
if (labelGlobalRefCount[fallLabel] > 1 && for (int i = 0; i < block.Body.Count - 1; i++) {
TryDuplicateReturn(scope, fallLabel, ref dupLabel)) { ILLabel curr = block.Body[i] as ILLabel;
labelGlobalRefCount[fallLabel]--; if (curr != null) {
labelGlobalRefCount[dupLabel] = 1; nextSibling[curr] = block.Body[i + 1];
head.FallthoughGoto.Operand = dupLabel;
modified = true;
}
}
if (head.Body.Count == 1) {
ILExpression brExpr = head.Body[0] as ILExpression;
if (brExpr != null && brExpr.Operand is ILLabel) {
ILLabel brLabel = (ILLabel)brExpr.Operand;
ILLabel dupLabel = null;
if (labelGlobalRefCount[brLabel] > 1 &&
TryDuplicateReturn(scope, brLabel, ref dupLabel)) {
labelGlobalRefCount[brLabel]--;
labelGlobalRefCount[dupLabel] = 1;
brExpr.Operand = dupLabel;
modified = true;
} }
} }
} }
return modified;
} // Duplicate returns
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
bool TryDuplicateReturn(List<ILNode> scope, ILLabel head, ref ILLabel newHead) for (int i = 0; i < block.Body.Count; i++) {
{ ILLabel targetLabel;
ILBasicBlock bb; if (block.Body[i].Match(ILCode.Br, out targetLabel) ||
// TODO: mapping missing? block.Body[i].Match(ILCode.Leave, out targetLabel))
if (labelToBasicBlock.TryGetValue(head, out bb) && bb.Body.Count == 1 && !scope.Contains(bb)) { {
ILExpression retExpr = bb.Body[0] as ILExpression; // Skip extra labels
if (retExpr != null && while(nextSibling.ContainsKey(targetLabel) && nextSibling[targetLabel] is ILLabel) {
retExpr.Prefixes == null && targetLabel = (ILLabel)nextSibling[targetLabel];
retExpr.Code == ILCode.Ret) }
{
if (retExpr.Arguments.Count == 0) { // Inline return statement
newHead = new ILLabel() { Name = "Return_" + (nextLabelIndex++) }; ILNode target;
ILBasicBlock newBB = new ILBasicBlock() { ILExpression retExpr;
EntryLabel = newHead, ILVariable locVar = null;
Body = { new ILExpression(ILCode.Ret, null) } if (nextSibling.TryGetValue(targetLabel, out target) &&
}; target.Match(ILCode.Ret, out retExpr) &&
scope.Add(newBB); (retExpr.Arguments.Count == 0 || retExpr.Arguments.Single().Match(ILCode.Ldloc, out locVar)))
labelToBasicBlock[newHead] = newBB;
return true;
} else {
ILExpression argExpr = retExpr.Arguments[0] as ILExpression;
if (argExpr != null &&
argExpr.Prefixes == null &&
argExpr.Code == ILCode.Ldloc)
{ {
newHead = new ILLabel() { Name = "Return_" + (nextLabelIndex++) }; ILExpression dup = new ILExpression(ILCode.Ret, null);
ILBasicBlock newBB = new ILBasicBlock() { if (locVar != null)
EntryLabel = newHead, dup.Arguments = new List<ILExpression>() { new ILExpression(ILCode.Ldloc, locVar) };
Body = { new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldloc, argExpr.Operand)) } block.Body[i] = dup;
};
scope.Add(newBB);
labelToBasicBlock[newHead] = newBB;
return true;
} }
} }
} }
} }
return false;
} }
ControlFlowGraph BuildGraph(List<ILNode> nodes, ILLabel entryLabel) ControlFlowGraph BuildGraph(List<ILNode> nodes, ILLabel entryLabel)
@ -798,10 +754,28 @@ namespace Decompiler.ControlFlow
public static class ILAstOptimizerExtensionMethods public static class ILAstOptimizerExtensionMethods
{ {
public static bool Matches(this ILNode node, ILCode code) public static bool Match(this ILNode node, ILCode code)
{ {
ILExpression expr = node as ILExpression; ILExpression expr = node as ILExpression;
return expr != null && expr.Prefixes == null && expr.Code == code; return expr != null && expr.Prefixes == null && expr.Code == code;
} }
public static bool Match(this ILNode node, ILCode code, out ILExpression expr)
{
expr = node as ILExpression;
return expr != null && expr.Prefixes == null && expr.Code == code;
}
public static bool Match<T>(this ILNode node, ILCode code, out T operand)
{
ILExpression expr = node as ILExpression;
if (expr != null && expr.Prefixes == null && expr.Code == code) {
operand = (T)expr.Operand;
return true;
} else {
operand = default(T);
return false;
}
}
} }
} }

Loading…
Cancel
Save