Browse Source

Reduce some 'goto's in loops to 'break' and 'continue'.

Do not output 'goto' for simple fall-through to next node.
pull/1/head^2
David Srbecký 18 years ago
parent
commit
ff56995219
  1. 56
      src/AstMetodBodyBuilder.cs
  2. 111
      src/ControlFlow/Node.cs

56
src/AstMetodBodyBuilder.cs

@ -74,9 +74,10 @@ namespace Decompiler
foreach(StackExpression expr in ((BasicBlock)node).Body) { foreach(StackExpression expr in ((BasicBlock)node).Body) {
yield return TransformExpression(expr); yield return TransformExpression(expr);
} }
Node next = ((BasicBlock)node).FallThroughBasicBlock; Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock;
if (next != null) { // If there is default branch and it is not the following node
yield return new Ast.GotoStatement(next.Label); if (fallThroughNode != null && fallThroughNode != node.NextNode) {
yield return MakeBranchCommand(node, fallThroughNode);
} }
} else if (node is AcyclicGraph) { } else if (node is AcyclicGraph) {
Ast.BlockStatement blockStatement = new Ast.BlockStatement(); Ast.BlockStatement blockStatement = new Ast.BlockStatement();
@ -152,17 +153,38 @@ namespace Decompiler
return MakeCodeDomExpression(methodDef, expr.LastByteCode, allArgs.ToArray()); return MakeCodeDomExpression(methodDef, expr.LastByteCode, allArgs.ToArray());
} }
static Ast.Statement MakeBranchCommand(Node node, Node targetNode)
{
// Propagate target up to the top most scope
while (targetNode.Parent != null && targetNode.Parent.HeadChild == targetNode) {
targetNode = targetNode.Parent;
}
// If branches to the start of encapsulating loop
if (node.Parent is Loop && targetNode == node.Parent) {
return new Ast.ContinueStatement();
}
// If branches outside the encapsulating loop
if (node.Parent is Loop && targetNode == node.Parent.NextNode) {
return new Ast.BreakStatement();
}
return new Ast.GotoStatement(targetNode.Label);
}
static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args) static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args)
{ {
OpCode opCode = byteCode.OpCode; OpCode opCode = byteCode.OpCode;
object operand = byteCode.Operand; object operand = byteCode.Operand;
Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null; Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null;
ByteCode operandAsByteCode = operand as ByteCode; ByteCode operandAsByteCode = operand as ByteCode;
string operandAsByteCodeLabel = operand is ByteCode ? ((ByteCode)operand).Expression.BasicBlock.Label : null;
Ast.Expression arg1 = args.Length >= 1 ? args[0] : null; Ast.Expression arg1 = args.Length >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Length >= 2 ? args[1] : null; Ast.Expression arg2 = args.Length >= 2 ? args[1] : null;
Ast.Expression arg3 = args.Length >= 3 ? args[2] : null; Ast.Expression arg3 = args.Length >= 3 ? args[2] : null;
Ast.Statement branchCommand = null;
if (operand is ByteCode) {
branchCommand = MakeBranchCommand(byteCode.Expression.BasicBlock, ((ByteCode)operand).Expression.BasicBlock);
}
switch(opCode.Code) { switch(opCode.Code) {
#region Arithmetic #region Arithmetic
case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -219,19 +241,19 @@ namespace Decompiler
case Code.Stelem_Any: throw new NotImplementedException(); case Code.Stelem_Any: throw new NotImplementedException();
#endregion #endregion
#region Branching #region Branching
case Code.Br: return new Ast.GotoStatement(operandAsByteCodeLabel); case Code.Br: return branchCommand;
case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), branchCommand);
case Code.Brtrue: return new Ast.IfElseStatement(arg1, new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Brtrue: return new Ast.IfElseStatement(arg1, branchCommand);
case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), branchCommand);
case Code.Bge: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Bge: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand);
case Code.Bge_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Bge_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand);
case Code.Bgt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Bgt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand);
case Code.Bgt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Bgt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand);
case Code.Ble: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Ble: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand);
case Code.Ble_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Ble_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand);
case Code.Blt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Blt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand);
case Code.Blt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Blt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand);
case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), new Ast.GotoStatement(operandAsByteCodeLabel)); case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand);
#endregion #endregion
#region Comparison #region Comparison
case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2)); case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2));

111
src/ControlFlow/Node.cs

@ -4,16 +4,16 @@ using System.Collections.Generic;
namespace Decompiler.ControlFlow namespace Decompiler.ControlFlow
{ {
public class Set<T>: System.Collections.ObjectModel.Collection<T> public class NodeCollection: System.Collections.ObjectModel.Collection<Node>
{ {
public void AddRange(IEnumerable<T> items) public void AddRange(IEnumerable<Node> items)
{ {
foreach(T item in items) { foreach(Node item in items) {
this.Add(item); this.Add(item);
} }
} }
protected override void InsertItem(int index, T item) protected override void InsertItem(int index, Node item)
{ {
if (!this.Contains(item)) { if (!this.Contains(item)) {
base.InsertItem(index, item); base.InsertItem(index, item);
@ -28,9 +28,9 @@ namespace Decompiler.ControlFlow
int id; int id;
Node parent; Node parent;
Node headChild; Node headChild;
Set<Node> childs = new Set<Node>(); NodeCollection childs = new NodeCollection();
Set<Node> predecessors = new Set<Node>(); NodeCollection predecessors = new NodeCollection();
Set<Node> successors = new Set<Node>(); NodeCollection successors = new NodeCollection();
public int ID { public int ID {
get { return id; } get { return id; }
@ -38,6 +38,7 @@ namespace Decompiler.ControlFlow
public Node Parent { public Node Parent {
get { return parent; } get { return parent; }
set { parent = value; }
} }
public Node HeadChild { public Node HeadChild {
@ -45,18 +46,31 @@ namespace Decompiler.ControlFlow
protected set { headChild = value; } protected set { headChild = value; }
} }
public Set<Node> Childs { public NodeCollection Childs {
get { return childs; } get { return childs; }
} }
public Set<Node> Predecessors { public NodeCollection Predecessors {
get { return predecessors; } get { return predecessors; }
} }
public Set<Node> Successors { public NodeCollection Successors {
get { return successors; } get { return successors; }
} }
public Node NextNode {
get {
if (this.Parent == null) throw new Exception("Does not have a parent");
int myIndex = this.Parent.Childs.IndexOf(this);
int index = myIndex + 1;
if (0 <= index && index < this.Parent.Childs.Count) {
return this.Parent.Childs[index];
} else {
return null;
}
}
}
public string Label { public string Label {
get { get {
return this.GetType().Name + "_" + ID; return this.GetType().Name + "_" + ID;
@ -85,6 +99,14 @@ namespace Decompiler.ControlFlow
if (this.Childs.Count == 1 && this.Childs[0] is AcyclicGraph) { if (this.Childs.Count == 1 && this.Childs[0] is AcyclicGraph) {
this.headChild = this.Childs[0].HeadChild; this.headChild = this.Childs[0].HeadChild;
this.childs = this.Childs[0].Childs; this.childs = this.Childs[0].Childs;
this.UpdateParentOfChilds();
}
}
void UpdateParentOfChilds()
{
foreach(Node child in this.Childs) {
child.Parent = this;
} }
} }
@ -128,6 +150,8 @@ namespace Decompiler.ControlFlow
throw new Exception("Invalid tail type"); throw new Exception("Invalid tail type");
} }
mergedNode.UpdateParentOfChilds();
// Remove links between the head and tail // Remove links between the head and tail
if (head.Successors.Contains(tail)) { if (head.Successors.Contains(tail)) {
head.Successors.Remove(tail); head.Successors.Remove(tail);
@ -175,39 +199,50 @@ namespace Decompiler.ControlFlow
sb.Append(ID); sb.Append(ID);
sb.Append(" "); sb.Append(" ");
if (this.Predecessors.Count > 0 || this.Successors.Count > 0) { sb.Append("(");
sb.Append("(");
if (this.Predecessors.Count > 0) { if (this.Predecessors.Count > 0) {
sb.Append("Predecessors:"); sb.Append("Predecessors:");
bool isFirst = true; bool isFirst = true;
foreach(Node predecessor in this.Predecessors) { foreach(Node predecessor in this.Predecessors) {
if (isFirst) { if (isFirst) {
isFirst = false; isFirst = false;
} else { } else {
sb.Append(","); sb.Append(",");
}
sb.Append(predecessor.ID);
} }
sb.Append(predecessor.ID);
} }
sb.Append(" ");
if (this.Predecessors.Count > 0 && this.Successors.Count > 0) { }
sb.Append(" ");
} if (this.Successors.Count > 0) {
sb.Append("Successors:");
if (this.Successors.Count > 0) { bool isFirst = true;
sb.Append("Successors:"); foreach(Node successor in this.Successors) {
bool isFirst = true; if (isFirst) {
foreach(Node successor in this.Successors) { isFirst = false;
if (isFirst) { } else {
isFirst = false; sb.Append(",");
} else {
sb.Append(",");
}
sb.Append(successor.ID);
} }
sb.Append(successor.ID);
} }
sb.Append(")"); sb.Append(" ");
}
if (this.Parent != null) {
sb.Append("Parent:");
sb.Append(this.Parent.ID);
} }
sb.Append(" ");
if (this.HeadChild != null) {
sb.Append("Head:");
sb.Append(this.HeadChild.ID);
}
sb.Append(" ");
sb.Length = sb.Length - 1;
sb.Append(")");
return sb.ToString(); return sb.ToString();
} }
} }

Loading…
Cancel
Save