From ff56995219d75aebc35fb3d4b6d2187d3db42bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 24 Jan 2008 23:37:18 +0000 Subject: [PATCH] Reduce some 'goto's in loops to 'break' and 'continue'. Do not output 'goto' for simple fall-through to next node. --- src/AstMetodBodyBuilder.cs | 56 +++++++++++++------ src/ControlFlow/Node.cs | 111 ++++++++++++++++++++++++------------- 2 files changed, 112 insertions(+), 55 deletions(-) diff --git a/src/AstMetodBodyBuilder.cs b/src/AstMetodBodyBuilder.cs index 347c1e1e5..229038d72 100644 --- a/src/AstMetodBodyBuilder.cs +++ b/src/AstMetodBodyBuilder.cs @@ -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 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 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)); diff --git a/src/ControlFlow/Node.cs b/src/ControlFlow/Node.cs index 65fbc8bfa..69a81c501 100644 --- a/src/ControlFlow/Node.cs +++ b/src/ControlFlow/Node.cs @@ -4,16 +4,16 @@ using System.Collections.Generic; namespace Decompiler.ControlFlow { - public class Set: System.Collections.ObjectModel.Collection + public class NodeCollection: System.Collections.ObjectModel.Collection { - public void AddRange(IEnumerable items) + public void AddRange(IEnumerable 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 int id; Node parent; Node headChild; - Set childs = new Set(); - Set predecessors = new Set(); - Set successors = new Set(); + 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 public Node Parent { get { return parent; } + set { parent = value; } } public Node HeadChild { @@ -45,18 +46,31 @@ namespace Decompiler.ControlFlow protected set { headChild = value; } } - public Set Childs { + public NodeCollection Childs { get { return childs; } } - public Set Predecessors { + public NodeCollection Predecessors { get { return predecessors; } } - public Set 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 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 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 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(); } }