Browse Source

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)
pull/1/head^2
David Srbecký 18 years ago
parent
commit
ecad71d802
  1. 6
      Decompiler.csproj
  2. 29
      src/AstMetodBodyBuilder.cs
  3. 32
      src/ControlFlow/Node-Structure.cs
  4. 40
      src/MyAst/MyGotoStatement.cs
  5. 21
      src/MyAst/MyLabelStatement.cs
  6. 19
      src/Transforms/Ast/RemoveDeadLabels.cs

6
Decompiler.csproj

@ -37,6 +37,9 @@
<ItemGroup> <ItemGroup>
<Folder Include="src" /> <Folder Include="src" />
<Folder Include="src\ControlFlow" /> <Folder Include="src\ControlFlow" />
<Folder Include="src\MyAst" />
<Folder Include="src\Transforms" />
<Folder Include="src\Transforms\Ast" />
<Compile Include="src\AssemblyInfo.cs" /> <Compile Include="src\AssemblyInfo.cs" />
<Compile Include="src\AstBuilder.cs" /> <Compile Include="src\AstBuilder.cs" />
<Compile Include="src\AstMetodBodyBuilder.cs" /> <Compile Include="src\AstMetodBodyBuilder.cs" />
@ -52,11 +55,14 @@
<Compile Include="src\ControlFlow\Node-Structure.cs" /> <Compile Include="src\ControlFlow\Node-Structure.cs" />
<Compile Include="src\MainForm.cs" /> <Compile Include="src\MainForm.cs" />
<Compile Include="src\MainForm.Designer.cs" /> <Compile Include="src\MainForm.Designer.cs" />
<Compile Include="src\MyAst\MyGotoStatement.cs" />
<Compile Include="src\MyAst\MyLabelStatement.cs" />
<Compile Include="src\Options.cs" /> <Compile Include="src\Options.cs" />
<Compile Include="src\Program.cs" /> <Compile Include="src\Program.cs" />
<Compile Include="src\ByteCode.StackAnalysis.cs" /> <Compile Include="src\ByteCode.StackAnalysis.cs" />
<Compile Include="src\StackExpression.cs" /> <Compile Include="src\StackExpression.cs" />
<Compile Include="src\StackExpressionCollection.cs" /> <Compile Include="src\StackExpressionCollection.cs" />
<Compile Include="src\Transforms\Ast\RemoveDeadLabels.cs" />
<Compile Include="src\Util.cs" /> <Compile Include="src\Util.cs" />
<EmbeddedResource Include="src\MainForm.resx"> <EmbeddedResource Include="src\MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon> <DependentUpon>MainForm.cs</DependentUpon>

29
src/AstMetodBodyBuilder.cs

@ -50,6 +50,8 @@ namespace Decompiler
astBlock.Children.AddRange(TransformNodes(bodyGraph.Childs)); astBlock.Children.AddRange(TransformNodes(bodyGraph.Childs));
astBlock.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null);
return astBlock; return astBlock;
} }
@ -68,7 +70,7 @@ namespace Decompiler
yield return MakeComment("// " + node.Description); yield return MakeComment("// " + node.Description);
} }
yield return new Ast.LabelStatement(node.Label); yield return new Ast.MyLabelStatement(node.Label);
if (node is BasicBlock) { if (node is BasicBlock) {
foreach(StackExpression expr in ((BasicBlock)node).Body) { foreach(StackExpression expr in ((BasicBlock)node).Body) {
@ -77,7 +79,7 @@ namespace Decompiler
Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock; Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock;
// If there is default branch and it is not the following node // If there is default branch and it is not the following node
if (fallThroughNode != null && fallThroughNode != node.NextNode) { if (fallThroughNode != null && fallThroughNode != node.NextNode) {
yield return MakeBranchCommand(node, fallThroughNode); yield return Ast.MyGotoStatement.Create(node, fallThroughNode);
} }
} else if (node is AcyclicGraph) { } else if (node is AcyclicGraph) {
Ast.BlockStatement blockStatement = new Ast.BlockStatement(); Ast.BlockStatement blockStatement = new Ast.BlockStatement();
@ -98,7 +100,7 @@ namespace Decompiler
} }
} else if (node is ConditionalNode) { } else if (node is ConditionalNode) {
ConditionalNode conditionalNode = (ConditionalNode)node; ConditionalNode conditionalNode = (ConditionalNode)node;
yield return new Ast.LabelStatement(conditionalNode.Condition.Label); yield return new Ast.MyLabelStatement(conditionalNode.Condition.Label);
Ast.Statement lastStatement = null; Ast.Statement lastStatement = null;
foreach(StackExpression expr in conditionalNode.Condition.Body) { foreach(StackExpression expr in conditionalNode.Condition.Body) {
lastStatement = TransformExpression(expr); lastStatement = TransformExpression(expr);
@ -112,7 +114,7 @@ namespace Decompiler
Ast.BlockStatement trueBlock = new Ast.BlockStatement(); Ast.BlockStatement trueBlock = new Ast.BlockStatement();
// The block entry code // The block entry code
trueBlock.Children.Add(MakeBranchCommand(node, conditionalNode.Condition.FallThroughBasicBlock)); trueBlock.Children.Add(Ast.MyGotoStatement.Create(node, conditionalNode.Condition.FallThroughBasicBlock));
// Sugested content // Sugested content
trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody)); trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody));
ifElseStmt.TrueStatement.Add(trueBlock); ifElseStmt.TrueStatement.Add(trueBlock);
@ -184,23 +186,6 @@ 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;
@ -213,7 +198,7 @@ namespace Decompiler
Ast.Statement branchCommand = null; Ast.Statement branchCommand = null;
if (operand is ByteCode) { 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) { switch(opCode.Code) {

32
src/ControlFlow/Node-Structure.cs

@ -9,6 +9,7 @@ namespace Decompiler.ControlFlow
public static int NextNodeID = 1; public static int NextNodeID = 1;
int id; int id;
NodeLabel label;
Node parent; Node parent;
NodeCollection childs = new NodeCollection(); NodeCollection childs = new NodeCollection();
@ -21,6 +22,10 @@ namespace Decompiler.ControlFlow
get { return id; } get { return id; }
} }
public NodeLabel Label {
get { return label; }
}
public Node Parent { public Node Parent {
get { return parent; } get { return parent; }
} }
@ -137,12 +142,6 @@ namespace Decompiler.ControlFlow
} }
} }
public string Label {
get {
return this.GetType().Name + "_" + ID;
}
}
public string Description { public string Description {
get { get {
return ToString(); return ToString();
@ -152,6 +151,7 @@ namespace Decompiler.ControlFlow
protected Node() protected Node()
{ {
this.id = NextNodeID++; this.id = NextNodeID++;
this.label = new NodeLabel(this.GetType().Name + "_" + ID);
this.Childs.Added += delegate(object sender, NodeEventArgs e) { this.Childs.Added += delegate(object sender, NodeEventArgs e) {
if (e.Node.Parent != null) { if (e.Node.Parent != null) {
throw new Exception("Node is already assigned to other parent"); throw new Exception("Node is already assigned to other parent");
@ -230,4 +230,24 @@ namespace Decompiler.ControlFlow
return sb.ToString(); 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;
}
}
} }

40
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);
}
}
}

21
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;
}
}
}

19
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;
}
}
}
Loading…
Cancel
Save