Browse Source

Label is not reference counted object anymore, it is just a string. During transform we in two passes - find all live labels - remove all dead ones (the rest).

pull/1/head^2
David Srbecký 18 years ago
parent
commit
35f06e0a4b
  1. 3
      Decompiler.csproj
  2. 27
      src/AstMetodBodyBuilder.cs
  3. 26
      src/ControlFlow/Node-Structure.cs
  4. 40
      src/MyAst/MyGotoStatement.cs
  5. 21
      src/MyAst/MyLabelStatement.cs
  6. 29
      src/Transforms/Ast/RemoveDeadLabels.cs
  7. 11
      src/Transforms/Ast/RemoveGotos.cs
  8. 7
      src/Transforms/Ast/RestoreLoop.cs

3
Decompiler.csproj

@ -44,7 +44,6 @@
<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" />
<Folder Include="src\Transforms\Ast" /> <Folder Include="src\Transforms\Ast" />
<Compile Include="src\AssemblyInfo.cs" /> <Compile Include="src\AssemblyInfo.cs" />
@ -62,8 +61,6 @@
<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" />

27
src/AstMetodBodyBuilder.cs

@ -77,7 +77,7 @@ namespace Decompiler
yield return MakeComment("// " + node.Description); yield return MakeComment("// " + node.Description);
} }
yield return new Ast.MyLabelStatement(node.Label); yield return new Ast.LabelStatement(node.Label);
if (node is BasicBlock) { if (node is BasicBlock) {
foreach(StackExpression expr in ((BasicBlock)node).Body) { foreach(StackExpression expr in ((BasicBlock)node).Body) {
@ -86,7 +86,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) { if (fallThroughNode != null) {
yield return Ast.MyGotoStatement.Create(node, fallThroughNode); 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();
@ -107,7 +107,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.MyLabelStatement(conditionalNode.Condition.Label); yield return new Ast.LabelStatement(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);
@ -121,7 +121,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(Ast.MyGotoStatement.Create(node, conditionalNode.Condition.FallThroughBasicBlock)); trueBlock.Children.Add(MakeBranchCommand(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);
@ -178,6 +178,23 @@ namespace Decompiler
return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); return new Ast.ExpressionStatement(new PrimitiveExpression(text, text));
} }
public static Ast.Statement MakeBranchCommand(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.GotoStatement(targetNode.Label);
}
static object MakeCodeDomExpression(MethodDefinition methodDef, StackExpression expr, params Ast.Expression[] args) static object MakeCodeDomExpression(MethodDefinition methodDef, StackExpression expr, params Ast.Expression[] args)
{ {
List<Ast.Expression> allArgs = new List<Ast.Expression>(); List<Ast.Expression> allArgs = new List<Ast.Expression>();
@ -207,7 +224,7 @@ namespace Decompiler
Ast.Statement branchCommand = null; Ast.Statement branchCommand = null;
if (operand is ByteCode) { if (operand is ByteCode) {
branchCommand = Ast.MyGotoStatement.Create(byteCode.Expression.BasicBlock, ((ByteCode)operand).Expression.BasicBlock); branchCommand = MakeBranchCommand(byteCode.Expression.BasicBlock, ((ByteCode)operand).Expression.BasicBlock);
} }
switch(opCode.Code) { switch(opCode.Code) {

26
src/ControlFlow/Node-Structure.cs

@ -9,7 +9,7 @@ namespace Decompiler.ControlFlow
public static int NextNodeID = 1; public static int NextNodeID = 1;
int id; int id;
NodeLabel label; string label;
Node parent; Node parent;
NodeCollection childs = new NodeCollection(); NodeCollection childs = new NodeCollection();
@ -22,7 +22,7 @@ namespace Decompiler.ControlFlow
get { return id; } get { return id; }
} }
public NodeLabel Label { public string Label {
get { return label; } get { return label; }
} }
@ -151,7 +151,7 @@ namespace Decompiler.ControlFlow
protected Node() protected Node()
{ {
this.id = NextNodeID++; this.id = NextNodeID++;
this.label = new NodeLabel(this.GetType().Name + "_" + ID); this.label = 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,24 +230,4 @@ 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

@ -1,40 +0,0 @@
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

@ -1,21 +0,0 @@
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;
}
}
}

29
src/Transforms/Ast/RemoveDeadLabels.cs

@ -1,5 +1,5 @@
using System; using System;
using System.Collections.Generic;
using Ast = ICSharpCode.NRefactory.Ast; using Ast = ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors; using ICSharpCode.NRefactory.Visitors;
@ -8,11 +8,32 @@ namespace Decompiler.Transforms.Ast
{ {
public class RemoveDeadLabels: AbstractAstTransformer public class RemoveDeadLabels: AbstractAstTransformer
{ {
List<string> usedLabels = new List<string>();
bool collectingUsedLabels;
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
{
collectingUsedLabels = true;
base.VisitMethodDeclaration(methodDeclaration, data);
collectingUsedLabels = false;
base.VisitMethodDeclaration(methodDeclaration, data);
return null;
}
public override object VisitGotoStatement(GotoStatement gotoStatement, object data)
{
if (collectingUsedLabels) {
usedLabels.Add(gotoStatement.Label);
}
return null;
}
public override object VisitLabelStatement(LabelStatement labelStatement, object data) public override object VisitLabelStatement(LabelStatement labelStatement, object data)
{ {
MyLabelStatement myLabel = (MyLabelStatement)labelStatement; if (!collectingUsedLabels) {
if (myLabel.NodeLabel.ReferenceCount == 0) { if (!usedLabels.Contains(labelStatement.Label)) {
RemoveCurrentNode(); RemoveCurrentNode();
}
} }
return null; return null;
} }

11
src/Transforms/Ast/RemoveGotos.cs

@ -39,10 +39,9 @@ namespace Decompiler.Transforms.Ast
if (lastStmt is GotoStatement && if (lastStmt is GotoStatement &&
blockStatement.Parent is IfElseStatement) blockStatement.Parent is IfElseStatement)
{ {
MyLabelStatement nextNodeAsLabel = blockStatement.Parent.Next() as MyLabelStatement; LabelStatement nextNodeAsLabel = blockStatement.Parent.Next() as LabelStatement;
if (nextNodeAsLabel != null) { if (nextNodeAsLabel != null) {
if (nextNodeAsLabel.NodeLabel == ((MyGotoStatement)lastStmt).NodeLabel) { if (nextNodeAsLabel.Label == ((GotoStatement)lastStmt).Label) {
((MyGotoStatement)lastStmt).NodeLabel.ReferenceCount--;
lastStmt.Remove(); lastStmt.Remove();
return null; return null;
} }
@ -54,10 +53,8 @@ namespace Decompiler.Transforms.Ast
public override object VisitGotoStatement(GotoStatement gotoStatement, object data) public override object VisitGotoStatement(GotoStatement gotoStatement, object data)
{ {
MyGotoStatement myGoto = (MyGotoStatement)gotoStatement; LabelStatement followingLabel = gotoStatement.Next() as LabelStatement;
MyLabelStatement followingLabel = myGoto.Next() as MyLabelStatement; if (followingLabel != null && followingLabel.Label == gotoStatement.Label) {
if (followingLabel != null && followingLabel.NodeLabel == myGoto.NodeLabel) {
myGoto.NodeLabel.ReferenceCount--;
RemoveCurrentNode(); RemoveCurrentNode();
} }
return null; return null;

7
src/Transforms/Ast/RestoreLoop.cs

@ -27,15 +27,14 @@ namespace Decompiler.Transforms.Ast
{ {
IfElseStatement condition = forStatement.EmbeddedStatement.Children[0] as IfElseStatement; IfElseStatement condition = forStatement.EmbeddedStatement.Children[0] as IfElseStatement;
BreakStatement breakStmt = forStatement.EmbeddedStatement.Children[1] as BreakStatement; BreakStatement breakStmt = forStatement.EmbeddedStatement.Children[1] as BreakStatement;
MyLabelStatement label = forStatement.EmbeddedStatement.Children[2] as MyLabelStatement; LabelStatement label = forStatement.EmbeddedStatement.Children[2] as LabelStatement;
if (condition != null && breakStmt != null && label != null && if (condition != null && breakStmt != null && label != null &&
condition.TrueStatement.Count == 1) condition.TrueStatement.Count == 1)
{ {
MyGotoStatement gotoStmt = condition.TrueStatement[0] as MyGotoStatement; GotoStatement gotoStmt = condition.TrueStatement[0] as GotoStatement;
if (gotoStmt != null && gotoStmt.NodeLabel == label.NodeLabel) { if (gotoStmt != null && gotoStmt.Label == label.Label) {
condition.Remove(); condition.Remove();
breakStmt.Remove(); breakStmt.Remove();
gotoStmt.NodeLabel.ReferenceCount--;
forStatement.Condition = condition.Condition; forStatement.Condition = condition.Condition;
} }
} }

Loading…
Cancel
Save