Browse Source

Resurrect Ast based "goto removal" - we will use that until it is converted to ILAst based one.

pull/10/head
David Srbecký 15 years ago
parent
commit
1ba93ac216
  1. 6
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 56
      ICSharpCode.Decompiler/Ast/Transforms/RemoveDeadLabels.cs
  3. 68
      ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs
  4. 53
      ICSharpCode.Decompiler/Ast/Transforms/RestoreLoop.cs
  5. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

6
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -19,11 +19,11 @@ namespace Decompiler
{ {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (Options.ReduceAstJumps) { if (Options.ReduceAstJumps) {
//astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null); astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null);
//astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null);
} }
if (Options.ReduceAstLoops) { if (Options.ReduceAstLoops) {
//astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null);
} }
if (Options.ReduceAstOther) { if (Options.ReduceAstOther) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null); astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null);

56
ICSharpCode.Decompiler/Ast/Transforms/RemoveDeadLabels.cs

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms.Ast
{
public class RemoveDeadLabels : DepthFirstAstVisitor<object, object>
{
List<string> usedLabels = new List<string>();
bool collectingUsedLabels;
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
{
collectingUsedLabels = true;
base.VisitConstructorDeclaration(constructorDeclaration, data);
collectingUsedLabels = false;
base.VisitConstructorDeclaration(constructorDeclaration, data);
return null;
}
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 VisitAccessor(Accessor accessor, object data)
{
collectingUsedLabels = true;
base.VisitAccessor(accessor, data);
collectingUsedLabels = false;
return base.VisitAccessor(accessor, data);
}
public override object VisitGotoStatement(GotoStatement gotoStatement, object data)
{
if (collectingUsedLabels) {
usedLabels.Add(gotoStatement.Label);
}
return null;
}
public override object VisitLabelStatement(LabelStatement labelStatement, object data)
{
if (!collectingUsedLabels) {
if (!usedLabels.Contains(labelStatement.Label)) {
labelStatement.Remove();
}
}
return null;
}
}
}

68
ICSharpCode.Decompiler/Ast/Transforms/RemoveGotos.cs

@ -1,16 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms.Ast namespace Decompiler.Transforms.Ast
{ {
/*
public class RemoveGotos: DepthFirstAstVisitor<object, object> public class RemoveGotos: DepthFirstAstVisitor<object, object>
{ {
Stack<Statement> enteredLoops = new Stack<Statement>(); Stack<ForStatement> enteredLoops = new Stack<ForStatement>();
Statement CurrentLoop { ForStatement CurrentLoop {
get { get {
if (enteredLoops.Count > 0) { if (enteredLoops.Count > 0) {
return enteredLoops.Peek(); return enteredLoops.Peek();
@ -28,27 +27,20 @@ namespace Decompiler.Transforms.Ast
return null; return null;
} }
public override object VisitWhileStatement(WhileStatement whileStatement, object data) // public override object VisitWhileStatement(WhileStatement whileStatement, object data)
{ // {
enteredLoops.Push(whileStatement); // enteredLoops.Push(whileStatement);
base.VisitWhileStatement(whileStatement, data); // base.VisitWhileStatement(whileStatement, data);
enteredLoops.Pop(); // enteredLoops.Pop();
return null; // return null;
} // }
public override object VisitBlockStatement(BlockStatement blockStatement, object data) public override object VisitBlockStatement(BlockStatement blockStatement, object data)
{ {
base.VisitBlockStatement(blockStatement, data); base.VisitBlockStatement(blockStatement, data);
// Remove redundant jump at the end of block // Remove redundant jump at the end of block
INode lastStmt = blockStatement.Children.Last; AstNode lastStmt = blockStatement.Children.LastOrDefault();
// End of while loop
if (lastStmt is ContinueStatement &&
blockStatement.Parent is DoLoopStatement)
{
lastStmt.Remove();
return null;
}
// End of for loop // End of for loop
if (lastStmt is ContinueStatement && if (lastStmt is ContinueStatement &&
blockStatement.Parent is ForStatement) blockStatement.Parent is ForStatement)
@ -74,7 +66,7 @@ namespace Decompiler.Transforms.Ast
{ {
if (statement == null) throw new ArgumentNullException(); if (statement == null) throw new ArgumentNullException();
Statement next = (Statement)statement.Next(); Statement next = (Statement)statement.NextSibling;
if (next != null) { if (next != null) {
return EnterBlockStatement(next); return EnterBlockStatement(next);
@ -104,12 +96,12 @@ namespace Decompiler.Transforms.Ast
// Iterator; Condition; Body // Iterator; Condition; Body
if (statement is ForStatement) { if (statement is ForStatement) {
ForStatement forLoop = statement as ForStatement; ForStatement forLoop = statement as ForStatement;
if (forLoop.Iterator.Count > 0) { if (forLoop.Iterators.Any()) {
return forLoop.Iterator[0]; return forLoop.Iterators.First();
} else if (!forLoop.Condition.IsNull) { } else if (!forLoop.Condition.IsNull) {
return forLoop.Condition; return forLoop.Condition;
} else { } else {
return EnterBlockStatement((Statement)forLoop.EmbeddedStatement.Children.First); return EnterBlockStatement((Statement)forLoop.EmbeddedStatement.FirstChild);
} }
} }
@ -124,14 +116,12 @@ namespace Decompiler.Transforms.Ast
// For loop starts as follows: Initializers; Condition; Body // For loop starts as follows: Initializers; Condition; Body
if (statement is ForStatement) { if (statement is ForStatement) {
ForStatement forLoop = statement as ForStatement; ForStatement forLoop = statement as ForStatement;
if (forLoop.Initializers.Count > 0) { if (forLoop.Initializers.Any()) {
return forLoop.Initializers[0]; return forLoop.Initializers.First();
} else if (!forLoop.Condition.IsNull) { } else if (!forLoop.Condition.IsNull) {
return forLoop.Condition; return forLoop.Condition;
} else if (forLoop.EmbeddedStatement is BlockStatement && } else if (forLoop.EmbeddedStatement.Children.FirstOrDefault() is Statement) {
forLoop.EmbeddedStatement.Children.Count > 0) { return EnterBlockStatement((Statement)forLoop.EmbeddedStatement.FirstChild); // Simplify again
statement = (Statement)forLoop.EmbeddedStatement.Children.First;
return EnterBlockStatement(statement); // Simplify again
} }
} }
@ -141,11 +131,11 @@ namespace Decompiler.Transforms.Ast
public override object VisitGotoStatement(GotoStatement gotoStatement, object data) public override object VisitGotoStatement(GotoStatement gotoStatement, object data)
{ {
// Remove redundant goto which goes to a label that imideately follows // Remove redundant goto which goes to a label that imideately follows
INode fallthoughTarget = GetNextStatement(gotoStatement); AstNode fallthoughTarget = GetNextStatement(gotoStatement);
while(true) { while(true) {
if (fallthoughTarget is LabelStatement) { if (fallthoughTarget is LabelStatement) {
if ((fallthoughTarget as LabelStatement).Label == gotoStatement.Label) { if ((fallthoughTarget as LabelStatement).Label == gotoStatement.Label) {
RemoveCurrentNode(); gotoStatement.Remove();
return null; return null;
} else { } else {
fallthoughTarget = GetNextStatement((LabelStatement)fallthoughTarget); fallthoughTarget = GetNextStatement((LabelStatement)fallthoughTarget);
@ -158,10 +148,10 @@ namespace Decompiler.Transforms.Ast
// Replace goto with 'break' // Replace goto with 'break'
// Break statement moves right outside the looop // Break statement moves right outside the looop
if (CurrentLoop != null) { if (CurrentLoop != null) {
INode breakTarget = GetNextStatement(CurrentLoop); AstNode breakTarget = GetNextStatement(CurrentLoop);
if ((breakTarget is LabelStatement) && if ((breakTarget is LabelStatement) &&
(breakTarget as LabelStatement).Label == gotoStatement.Label) { (breakTarget as LabelStatement).Label == gotoStatement.Label) {
ReplaceCurrentNode(new BreakStatement()); gotoStatement.ReplaceWith(new BreakStatement());
return null; return null;
} }
} }
@ -170,24 +160,24 @@ namespace Decompiler.Transforms.Ast
// Continue statement which moves at the very end of loop // Continue statement which moves at the very end of loop
if (CurrentLoop != null && if (CurrentLoop != null &&
(CurrentLoop.EmbeddedStatement is BlockStatement) && (CurrentLoop.EmbeddedStatement is BlockStatement) &&
((CurrentLoop.EmbeddedStatement as BlockStatement).Children.Last as LabelStatement) != null && ((CurrentLoop.EmbeddedStatement as BlockStatement).LastChild as LabelStatement) != null &&
((CurrentLoop.EmbeddedStatement as BlockStatement).Children.Last as LabelStatement).Label == gotoStatement.Label) { ((CurrentLoop.EmbeddedStatement as BlockStatement).LastChild as LabelStatement).Label == gotoStatement.Label) {
ReplaceCurrentNode(new ContinueStatement()); gotoStatement.ReplaceWith(new ContinueStatement());
return null; return null;
} }
// Replace goto with 'continue' // Replace goto with 'continue'
// Continue statement which moves at the very start of for loop // Continue statement which moves at the very start of for loop
if (CurrentLoop != null) { if (CurrentLoop != null) {
INode continueTarget = ExitBlockStatement(CurrentLoop); // The start of the loop AstNode continueTarget = ExitBlockStatement(CurrentLoop); // The start of the loop
if ((continueTarget is LabelStatement) && if ((continueTarget is LabelStatement) &&
(continueTarget as LabelStatement).Label == gotoStatement.Label) { (continueTarget as LabelStatement).Label == gotoStatement.Label) {
ReplaceCurrentNode(new ContinueStatement()); gotoStatement.ReplaceWith(new ContinueStatement());
return null; return null;
} }
} }
return null; return null;
} }
}*/ }
} }

53
ICSharpCode.Decompiler/Ast/Transforms/RestoreLoop.cs

@ -1,10 +1,9 @@
using System; using System;
using System.Linq;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms.Ast namespace Decompiler.Transforms.Ast
{ {
/*
public class RestoreLoop: DepthFirstAstVisitor<object, object> public class RestoreLoop: DepthFirstAstVisitor<object, object>
{ {
public override object VisitForStatement(ForStatement forStatement, object data) public override object VisitForStatement(ForStatement forStatement, object data)
@ -12,25 +11,25 @@ namespace Decompiler.Transforms.Ast
base.VisitForStatement(forStatement, data); base.VisitForStatement(forStatement, data);
// Restore loop initializer // Restore loop initializer
if (forStatement.Initializers.Count == 0) { if (!forStatement.Initializers.Any()) {
LocalVariableDeclaration varDeclr = forStatement.Previous() as LocalVariableDeclaration; VariableDeclarationStatement varDeclr = forStatement.PrevSibling as VariableDeclarationStatement;
if (varDeclr != null) { if (varDeclr != null) {
varDeclr.ReplaceWith(Statement.Null); varDeclr.ReplaceWith(Statement.Null);
forStatement.Initializers.Add(varDeclr); forStatement.Initializers = new Statement[] { varDeclr };
} }
} }
// Restore loop condition // Restore loop condition
if (forStatement.Condition.IsNull && if (forStatement.Condition.IsNull &&
forStatement.EmbeddedStatement.Children.Count >= 3) forStatement.EmbeddedStatement.Children.Count() >= 3)
{ {
IfElseStatement condition = forStatement.EmbeddedStatement.Children[0] as IfElseStatement; IfElseStatement condition = forStatement.EmbeddedStatement.Children.First() as IfElseStatement;
BreakStatement breakStmt = forStatement.EmbeddedStatement.Children[1] as BreakStatement; BreakStatement breakStmt = forStatement.EmbeddedStatement.Children.Skip(1).First() as BreakStatement;
LabelStatement label = forStatement.EmbeddedStatement.Children[2] as LabelStatement; LabelStatement label = forStatement.EmbeddedStatement.Children.Skip(2).First() as LabelStatement;
if (condition != null && breakStmt != null && label != null && if (condition != null && breakStmt != null && label != null &&
condition.TrueStatement.Count == 1) condition.TrueStatement.Children.Count() == 1)
{ {
GotoStatement gotoStmt = condition.TrueStatement[0] as GotoStatement; GotoStatement gotoStmt = condition.TrueStatement.FirstChild as GotoStatement;
if (gotoStmt != null && gotoStmt.Label == label.Label) { if (gotoStmt != null && gotoStmt.Label == label.Label) {
condition.Remove(); condition.Remove();
breakStmt.Remove(); breakStmt.Remove();
@ -41,34 +40,34 @@ namespace Decompiler.Transforms.Ast
// Restore loop condition (version 2) // Restore loop condition (version 2)
if (forStatement.Condition.IsNull) { if (forStatement.Condition.IsNull) {
IfElseStatement condition = forStatement.EmbeddedStatement.Children.First as IfElseStatement; IfElseStatement condition = forStatement.EmbeddedStatement.FirstChild as IfElseStatement;
if (condition != null && if (condition != null &&
condition.TrueStatement.Count == 1 && condition.TrueStatement.Children.Any() &&
condition.TrueStatement[0] is BlockStatement && condition.TrueStatement.FirstChild is BlockStatement &&
condition.TrueStatement[0].Children.Count == 1 && condition.TrueStatement.Children.Count() == 1 &&
condition.TrueStatement[0].Children.First is BreakStatement && condition.TrueStatement.FirstChild.FirstChild is BreakStatement &&
condition.FalseStatement.Count == 1 && condition.FalseStatement.Children.Any() &&
condition.FalseStatement[0] is BlockStatement && condition.FalseStatement.FirstChild is BlockStatement &&
condition.FalseStatement[0].Children.Count == 0) condition.FalseStatement.Children.Count() == 0)
{ {
condition.Remove(); condition.Remove();
forStatement.Condition = new UnaryOperatorExpression(condition.Condition, UnaryOperatorType.Not); forStatement.Condition = new UnaryOperatorExpression() { Expression = condition.Condition, Operator = UnaryOperatorType.Not };
} }
} }
// Restore loop iterator // Restore loop iterator
if (forStatement.EmbeddedStatement.Children.Count > 0 && if (forStatement.EmbeddedStatement.Children.Any() &&
forStatement.Iterator.Count == 0) !forStatement.Iterators.Any())
{ {
ExpressionStatement lastStmt = forStatement.EmbeddedStatement.Children.Last as ExpressionStatement; ExpressionStatement lastStmt = forStatement.EmbeddedStatement.LastChild as ExpressionStatement;
if (lastStmt != null && if (lastStmt != null &&
(lastStmt.Expression is AssignmentExpression || lastStmt.Expression is UnaryOperatorExpression)) { (lastStmt.Expression is AssignmentExpression || lastStmt.Expression is UnaryOperatorExpression)) {
lastStmt.Remove(); lastStmt.Remove();
forStatement.Iterator.Add(lastStmt); forStatement.Iterators = new Statement[] { lastStmt };
} }
} }
return null; return null;
} }
}*/ }
} }

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -57,6 +57,7 @@
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" /> <Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" /> <Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" />
<Compile Include="Ast\Transforms\PushNegation.cs" /> <Compile Include="Ast\Transforms\PushNegation.cs" />
<Compile Include="Ast\Transforms\RemoveDeadLabels.cs" />
<Compile Include="Ast\Transforms\RemoveEmptyElseBody.cs" /> <Compile Include="Ast\Transforms\RemoveEmptyElseBody.cs" />
<Compile Include="Ast\Transforms\RemoveGotos.cs" /> <Compile Include="Ast\Transforms\RemoveGotos.cs" />
<Compile Include="Ast\Transforms\RestoreLoop.cs" /> <Compile Include="Ast\Transforms\RestoreLoop.cs" />

Loading…
Cancel
Save