From ecad71d8022e5afad6ae85fd79360c89b7a72d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Sun, 27 Jan 2008 15:43:40 +0000 Subject: [PATCH] Added custom Ast classes for Goto and Label statements that track the reference count of a label. Added an Ast transform to remove dead labels. (first Ast transform in program, I expect many more to come. Some stuff should be rewritten to use these explicit transforms) --- Decompiler.csproj | 6 ++++ src/AstMetodBodyBuilder.cs | 29 +++++-------------- src/ControlFlow/Node-Structure.cs | 32 +++++++++++++++++---- src/MyAst/MyGotoStatement.cs | 40 ++++++++++++++++++++++++++ src/MyAst/MyLabelStatement.cs | 21 ++++++++++++++ src/Transforms/Ast/RemoveDeadLabels.cs | 19 ++++++++++++ 6 files changed, 119 insertions(+), 28 deletions(-) create mode 100644 src/MyAst/MyGotoStatement.cs create mode 100644 src/MyAst/MyLabelStatement.cs create mode 100644 src/Transforms/Ast/RemoveDeadLabels.cs diff --git a/Decompiler.csproj b/Decompiler.csproj index 19eec5f21..eda362fbd 100644 --- a/Decompiler.csproj +++ b/Decompiler.csproj @@ -37,6 +37,9 @@ + + + @@ -52,11 +55,14 @@ + + + MainForm.cs diff --git a/src/AstMetodBodyBuilder.cs b/src/AstMetodBodyBuilder.cs index 0e5380bb8..0e5659825 100644 --- a/src/AstMetodBodyBuilder.cs +++ b/src/AstMetodBodyBuilder.cs @@ -50,6 +50,8 @@ namespace Decompiler astBlock.Children.AddRange(TransformNodes(bodyGraph.Childs)); + astBlock.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); + return astBlock; } @@ -68,7 +70,7 @@ namespace Decompiler yield return MakeComment("// " + node.Description); } - yield return new Ast.LabelStatement(node.Label); + yield return new Ast.MyLabelStatement(node.Label); if (node is BasicBlock) { foreach(StackExpression expr in ((BasicBlock)node).Body) { @@ -77,7 +79,7 @@ namespace Decompiler 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); + yield return Ast.MyGotoStatement.Create(node, fallThroughNode); } } else if (node is AcyclicGraph) { Ast.BlockStatement blockStatement = new Ast.BlockStatement(); @@ -98,7 +100,7 @@ namespace Decompiler } } else if (node is ConditionalNode) { ConditionalNode conditionalNode = (ConditionalNode)node; - yield return new Ast.LabelStatement(conditionalNode.Condition.Label); + yield return new Ast.MyLabelStatement(conditionalNode.Condition.Label); Ast.Statement lastStatement = null; foreach(StackExpression expr in conditionalNode.Condition.Body) { lastStatement = TransformExpression(expr); @@ -112,7 +114,7 @@ namespace Decompiler Ast.BlockStatement trueBlock = new Ast.BlockStatement(); // The block entry code - trueBlock.Children.Add(MakeBranchCommand(node, conditionalNode.Condition.FallThroughBasicBlock)); + trueBlock.Children.Add(Ast.MyGotoStatement.Create(node, conditionalNode.Condition.FallThroughBasicBlock)); // Sugested content trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody)); ifElseStmt.TrueStatement.Add(trueBlock); @@ -184,23 +186,6 @@ 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; @@ -213,7 +198,7 @@ namespace Decompiler Ast.Statement branchCommand = null; if (operand is ByteCode) { - branchCommand = MakeBranchCommand(byteCode.Expression.BasicBlock, ((ByteCode)operand).Expression.BasicBlock); + branchCommand = Ast.MyGotoStatement.Create(byteCode.Expression.BasicBlock, ((ByteCode)operand).Expression.BasicBlock); } switch(opCode.Code) { diff --git a/src/ControlFlow/Node-Structure.cs b/src/ControlFlow/Node-Structure.cs index e588c488c..53cbc763c 100644 --- a/src/ControlFlow/Node-Structure.cs +++ b/src/ControlFlow/Node-Structure.cs @@ -9,6 +9,7 @@ namespace Decompiler.ControlFlow public static int NextNodeID = 1; int id; + NodeLabel label; Node parent; NodeCollection childs = new NodeCollection(); @@ -21,6 +22,10 @@ namespace Decompiler.ControlFlow get { return id; } } + public NodeLabel Label { + get { return label; } + } + public Node Parent { get { return parent; } } @@ -137,12 +142,6 @@ namespace Decompiler.ControlFlow } } - public string Label { - get { - return this.GetType().Name + "_" + ID; - } - } - public string Description { get { return ToString(); @@ -152,6 +151,7 @@ namespace Decompiler.ControlFlow protected Node() { this.id = NextNodeID++; + this.label = new NodeLabel(this.GetType().Name + "_" + ID); this.Childs.Added += delegate(object sender, NodeEventArgs e) { if (e.Node.Parent != null) { throw new Exception("Node is already assigned to other parent"); @@ -230,4 +230,24 @@ namespace Decompiler.ControlFlow return sb.ToString(); } } + + public class NodeLabel + { + string label; + int referenceCount = 0; + + public string Label { + get { return label; } + } + + public int ReferenceCount { + get { return referenceCount; } + set { referenceCount = value; } + } + + public NodeLabel(string label) + { + this.label = label; + } + } } diff --git a/src/MyAst/MyGotoStatement.cs b/src/MyAst/MyGotoStatement.cs new file mode 100644 index 000000000..18b6f550f --- /dev/null +++ b/src/MyAst/MyGotoStatement.cs @@ -0,0 +1,40 @@ +using System; + +using Ast = ICSharpCode.NRefactory.Ast; +using Decompiler.ControlFlow; + +namespace ICSharpCode.NRefactory.Ast +{ + public class MyGotoStatement: Ast.GotoStatement + { + NodeLabel nodeLabel; + + public NodeLabel NodeLabel { + get { return nodeLabel; } + } + + public MyGotoStatement(NodeLabel nodeLabel): base(nodeLabel.Label) + { + this.nodeLabel = nodeLabel; + + this.nodeLabel.ReferenceCount++; + } + + public static Ast.Statement Create(Node contextNode, 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 (contextNode.Parent is Loop && targetNode == contextNode.Parent) { + return new Ast.ContinueStatement(); + } + // If branches outside the encapsulating loop + if (contextNode.Parent is Loop && targetNode == contextNode.Parent.NextNode) { + return new Ast.BreakStatement(); + } + return new Ast.MyGotoStatement(targetNode.Label); + } + } +} diff --git a/src/MyAst/MyLabelStatement.cs b/src/MyAst/MyLabelStatement.cs new file mode 100644 index 000000000..007c2a792 --- /dev/null +++ b/src/MyAst/MyLabelStatement.cs @@ -0,0 +1,21 @@ +using System; + +using Ast = ICSharpCode.NRefactory.Ast; +using Decompiler.ControlFlow; + +namespace ICSharpCode.NRefactory.Ast +{ + public class MyLabelStatement: Ast.LabelStatement + { + NodeLabel nodeLabel; + + public NodeLabel NodeLabel { + get { return nodeLabel; } + } + + public MyLabelStatement(NodeLabel nodeLabel): base(nodeLabel.Label) + { + this.nodeLabel = nodeLabel; + } + } +} diff --git a/src/Transforms/Ast/RemoveDeadLabels.cs b/src/Transforms/Ast/RemoveDeadLabels.cs new file mode 100644 index 000000000..18b742d91 --- /dev/null +++ b/src/Transforms/Ast/RemoveDeadLabels.cs @@ -0,0 +1,19 @@ +using System; + +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; + +namespace Decompiler.Transforms.Ast +{ + public class RemoveDeadLabels: AbstractAstTransformer + { + public override object VisitLabelStatement(LabelStatement labelStatement, object data) + { + MyLabelStatement myLabel = (MyLabelStatement)labelStatement; + if (myLabel.NodeLabel.ReferenceCount == 0) { + RemoveCurrentNode(); + } + return null; + } + } +}