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 @@ -74,9 +74,10 @@ namespace Decompiler
foreach(StackExpression expr in ((BasicBlock)node).Body) {
yield return TransformExpression(expr);
}
Node next = ((BasicBlock)node).FallThroughBasicBlock;
if (next != null) {
yield return new Ast.GotoStatement(next.Label);
Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock;
// If there is default branch and it is not the following node
if (fallThroughNode != null && fallThroughNode != node.NextNode) {
yield return MakeBranchCommand(node, fallThroughNode);
}
} else if (node is AcyclicGraph) {
Ast.BlockStatement blockStatement = new Ast.BlockStatement();
@ -152,17 +153,38 @@ namespace Decompiler @@ -152,17 +153,38 @@ namespace Decompiler
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)
{
OpCode opCode = byteCode.OpCode;
object operand = byteCode.Operand;
Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null;
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 arg2 = args.Length >= 2 ? args[1] : 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) {
#region Arithmetic
case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -219,19 +241,19 @@ namespace Decompiler @@ -219,19 +241,19 @@ namespace Decompiler
case Code.Stelem_Any: throw new NotImplementedException();
#endregion
#region Branching
case Code.Br: return new Ast.GotoStatement(operandAsByteCodeLabel);
case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Brtrue: return new Ast.IfElseStatement(arg1, new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Bge: 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), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Bgt: 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), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Ble: 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), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Blt: 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), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Br: return branchCommand;
case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), branchCommand);
case Code.Brtrue: return new Ast.IfElseStatement(arg1, branchCommand);
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), branchCommand);
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), branchCommand);
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), branchCommand);
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), branchCommand);
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), branchCommand);
#endregion
#region Comparison
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; @@ -4,16 +4,16 @@ using System.Collections.Generic;
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);
}
}
protected override void InsertItem(int index, T item)
protected override void InsertItem(int index, Node item)
{
if (!this.Contains(item)) {
base.InsertItem(index, item);
@ -28,9 +28,9 @@ namespace Decompiler.ControlFlow @@ -28,9 +28,9 @@ namespace Decompiler.ControlFlow
int id;
Node parent;
Node headChild;
Set<Node> childs = new Set<Node>();
Set<Node> predecessors = new Set<Node>();
Set<Node> successors = new Set<Node>();
NodeCollection childs = new NodeCollection();
NodeCollection predecessors = new NodeCollection();
NodeCollection successors = new NodeCollection();
public int ID {
get { return id; }
@ -38,6 +38,7 @@ namespace Decompiler.ControlFlow @@ -38,6 +38,7 @@ namespace Decompiler.ControlFlow
public Node Parent {
get { return parent; }
set { parent = value; }
}
public Node HeadChild {
@ -45,18 +46,31 @@ namespace Decompiler.ControlFlow @@ -45,18 +46,31 @@ namespace Decompiler.ControlFlow
protected set { headChild = value; }
}
public Set<Node> Childs {
public NodeCollection Childs {
get { return childs; }
}
public Set<Node> Predecessors {
public NodeCollection Predecessors {
get { return predecessors; }
}
public Set<Node> Successors {
public NodeCollection 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 {
get {
return this.GetType().Name + "_" + ID;
@ -85,6 +99,14 @@ namespace Decompiler.ControlFlow @@ -85,6 +99,14 @@ namespace Decompiler.ControlFlow
if (this.Childs.Count == 1 && this.Childs[0] is AcyclicGraph) {
this.headChild = this.Childs[0].HeadChild;
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 @@ -128,6 +150,8 @@ namespace Decompiler.ControlFlow
throw new Exception("Invalid tail type");
}
mergedNode.UpdateParentOfChilds();
// Remove links between the head and tail
if (head.Successors.Contains(tail)) {
head.Successors.Remove(tail);
@ -175,39 +199,50 @@ namespace Decompiler.ControlFlow @@ -175,39 +199,50 @@ namespace Decompiler.ControlFlow
sb.Append(ID);
sb.Append(" ");
if (this.Predecessors.Count > 0 || this.Successors.Count > 0) {
sb.Append("(");
if (this.Predecessors.Count > 0) {
sb.Append("Predecessors:");
bool isFirst = true;
foreach(Node predecessor in this.Predecessors) {
if (isFirst) {
isFirst = false;
} else {
sb.Append(",");
}
sb.Append(predecessor.ID);
sb.Append("(");
if (this.Predecessors.Count > 0) {
sb.Append("Predecessors:");
bool isFirst = true;
foreach(Node predecessor in this.Predecessors) {
if (isFirst) {
isFirst = false;
} else {
sb.Append(",");
}
sb.Append(predecessor.ID);
}
if (this.Predecessors.Count > 0 && this.Successors.Count > 0) {
sb.Append(" ");
}
if (this.Successors.Count > 0) {
sb.Append("Successors:");
bool isFirst = true;
foreach(Node successor in this.Successors) {
if (isFirst) {
isFirst = false;
} else {
sb.Append(",");
}
sb.Append(successor.ID);
sb.Append(" ");
}
if (this.Successors.Count > 0) {
sb.Append("Successors:");
bool isFirst = true;
foreach(Node successor in this.Successors) {
if (isFirst) {
isFirst = false;
} else {
sb.Append(",");
}
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();
}
}

Loading…
Cancel
Save