Browse Source

Merge branch 'master' of github.com:icsharpcode/ILSpy

pull/10/head
Daniel Grunwald 15 years ago
parent
commit
f40229d00c
  1. 2
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 217
      ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs
  3. 56
      ICSharpCode.Decompiler/Ast/Transforms/RemoveDeadLabels.cs
  4. 5
      ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs
  5. 240
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  6. 188
      ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Optimize.cs
  7. 233
      ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Structure.cs
  8. 60
      ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Transforms.cs
  9. 130
      ICSharpCode.Decompiler/ILAst/ControlFlow/NodeCollection.cs
  10. 254
      ICSharpCode.Decompiler/ILAst/ControlFlow/Nodes.cs
  11. 4
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  12. 456
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  13. 115
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

2
ICSharpCode.Decompiler/Ast/AstBuilder.cs

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

217
ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Ast = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp;
using Cecil = Mono.Cecil;
@ -21,17 +22,7 @@ namespace Decompiler @@ -21,17 +22,7 @@ namespace Decompiler
{
AstMethodBodyBuilder builder = new AstMethodBodyBuilder();
builder.methodDef = methodDef;
if (Debugger.IsAttached) {
return builder.CreateMethodBody();
} else {
try {
return builder.CreateMethodBody();
} catch {
BlockStatement block = new BlockStatement();
block.AddChild(new Comment("// Exception during decompilation"), BlockStatement.Roles.Comment);
return block;
}
}
return builder.CreateMethodBody();
}
static readonly Dictionary<string, string> typeNameToVariableNameDict = new Dictionary<string, string> {
@ -57,8 +48,8 @@ namespace Decompiler @@ -57,8 +48,8 @@ namespace Decompiler
List<ILNode> body = new ILAstBuilder().Build(methodDef, true);
MethodBodyGraph bodyGraph = new MethodBodyGraph(body);
bodyGraph.Optimize();
ILAstOptimizer bodyGraph = new ILAstOptimizer();
bodyGraph.Optimize(ref body);
List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"});
Dictionary<string, int> typeNames = new Dictionary<string, int>();
@ -104,62 +95,42 @@ namespace Decompiler @@ -104,62 +95,42 @@ namespace Decompiler
// astBlock.Children.Add(astLocalVar);
}
Ast.BlockStatement astBlock = new Ast.BlockStatement();
astBlock.Statements = TransformNodes(bodyGraph.Childs);
Ast.BlockStatement astBlock = TransformBlock(new ILBlock(body));
CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
return astBlock;
}
IEnumerable<Statement> TransformNodes(IEnumerable<Node> nodes)
Ast.BlockStatement TransformBlock(ILBlock block)
{
foreach(Node node in nodes) {
foreach(Ast.Statement stmt in TransformNode(node)) {
yield return stmt;
Ast.BlockStatement astBlock = new BlockStatement();
if (block != null) {
foreach(ILNode node in block.Body) {
astBlock.AddStatements(TransformNode(node));
}
}
return astBlock;
}
IEnumerable<Statement> TransformNode(Node node)
IEnumerable<Statement> TransformNode(ILNode node)
{
if (Options.NodeComments) {
yield return new CommentStatement(node.Description);
}
yield return new Ast.LabelStatement { Label = node.Label };
if (node is BasicBlock) {
foreach(ILNode expr in ((BasicBlock)node).Body) {
if (expr is ILLabel) {
yield return new Ast.LabelStatement { Label = ((ILLabel)expr).Name };
if (node is ILLabel) {
yield return new Ast.LabelStatement { Label = ((ILLabel)node).Name };
} else if (node is ILExpression) {
object codeExpr = TransformExpression((ILExpression)node);
if (codeExpr != null) {
if (codeExpr is Ast.Expression) {
yield return new Ast.ExpressionStatement { Expression = (Ast.Expression)codeExpr };
} else if (codeExpr is Ast.Statement) {
yield return (Ast.Statement)codeExpr;
} else {
Statement stmt = TransformExpressionToStatement((ILExpression)expr);
if (stmt != null) {
yield return stmt;
}
throw new Exception();
}
}
foreach(Statement inode in TransformNodes(node.Childs)) {
yield return inode;
}
Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock;
// If there is default branch and it is not the following node
if (fallThroughNode != null) {
yield return new Ast.GotoStatement { GotoType = GotoType.Label, Label = fallThroughNode.Label };
}
} else if (node is AcyclicGraph) {
foreach(Statement inode in TransformNodes(node.Childs)) {
yield return inode;
}
} else if (node is Loop) {
Ast.BlockStatement blockStatement = new Ast.BlockStatement();
blockStatement.Statements = TransformNodes(node.Childs);
} else if (node is ILLoop) {
yield return new Ast.ForStatement {
EmbeddedStatement = blockStatement
EmbeddedStatement = TransformBlock(((ILLoop)node).ContentBlock)
};
} else if (node is Block) {
foreach(Statement inode in TransformNodes(node.Childs)) {
yield return inode;
}
/*
} else if (node is Branch) {
yield return new Ast.LabelStatement { Label = ((Branch)node).FirstBasicBlock.Label };
@ -176,62 +147,34 @@ namespace Decompiler @@ -176,62 +147,34 @@ namespace Decompiler
};
yield return ifElseStmt;
} else if (node is ConditionalNode) {
ConditionalNode conditionalNode = (ConditionalNode)node;
yield return new Ast.LabelStatement { Label = conditionalNode.Condition.FirstBasicBlock.Label };
Ast.BlockStatement trueBlock = new Ast.BlockStatement();
// The block entry code
trueBlock.AddStatement(new Ast.GotoStatement(conditionalNode.Condition.TrueSuccessor.Label));
// Sugested content
trueBlock.AddStatements(TransformNode(conditionalNode.TrueBody));
Ast.BlockStatement falseBlock = new Ast.BlockStatement();
// The block entry code
falseBlock.AddStatement(new Ast.GotoStatement(conditionalNode.Condition.FalseSuccessor.Label));
// Sugested content
falseBlock.AddStatements(TransformNode(conditionalNode.FalseBody));
Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement {
// Method bodies are swapped
Condition = new Ast.UnaryOperatorExpression(
UnaryOperatorType.Not,
MakeBranchCondition(conditionalNode.Condition)
),
TrueStatement = falseBlock,
FalseStatement = trueBlock
*/
} else if (node is ILCondition) {
ILCondition conditionalNode = (ILCondition)node;
// Swap bodies
yield return new Ast.IfElseStatement {
Condition = new UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(conditionalNode.Condition)),
TrueStatement = TransformBlock(conditionalNode.FalseBlock),
FalseStatement = TransformBlock(conditionalNode.TrueBlock)
};
yield return ifElseStmt;
} else if (node is TryCatchNode) {
TryCatchNode tryCachNode = ((TryCatchNode)node);
Ast.BlockStatement tryBlock = new Ast.BlockStatement();
tryBlock.Statements = TransformNode(tryCachNode.Childs[0]);
Ast.BlockStatement finallyBlock = null;
if (tryCachNode.Childs[1].Childs.Count > 0) {
finallyBlock = new Ast.BlockStatement();
finallyBlock.Statements = TransformNode(tryCachNode.Childs[1]);
}
List<Ast.CatchClause> ccs = new List<CatchClause>();
for (int i = 0; i < tryCachNode.Types.Count; i++) {
Ast.BlockStatement catchBlock = new Ast.BlockStatement();
catchBlock.Statements = TransformNode(tryCachNode.Childs[i + 2]);
Ast.CatchClause cc = new Ast.CatchClause {
Type = AstBuilder.ConvertType(tryCachNode.Types[i]),
} else if (node is ILTryCatchBlock) {
ILTryCatchBlock tryCachNode = ((ILTryCatchBlock)node);
List<Ast.CatchClause> catchClauses = new List<CatchClause>();
foreach (var catchClause in tryCachNode.CatchBlocks) {
catchClauses.Add(new Ast.CatchClause {
Type = AstBuilder.ConvertType(catchClause.ExceptionType),
VariableName = "exception",
Body = catchBlock
};
ccs.Add(cc);
Body = TransformBlock(catchClause)
});
}
yield return new Ast.TryCatchStatement {
TryBlock = tryBlock, CatchClauses = ccs, FinallyBlock = finallyBlock
TryBlock = TransformBlock(tryCachNode.TryBlock),
CatchClauses = catchClauses,
FinallyBlock = TransformBlock(tryCachNode.FinallyBlock)
};
} else if (node is ILBlock) {
yield return TransformBlock((ILBlock)node);
} else {
throw new Exception("Bad node type");
}
if (Options.NodeComments) {
yield return new CommentStatement("");
throw new Exception("Unknown node type");
}
}
@ -251,47 +194,27 @@ namespace Decompiler @@ -251,47 +194,27 @@ namespace Decompiler
return TransformByteCode(methodDef, expr, args);
}
Ast.Statement TransformExpressionToStatement(ILExpression expr)
Ast.Expression MakeBranchCondition(ILExpression expr)
{
object codeExpr = TransformExpression(expr);
if (codeExpr == null) {
return null;
} else if (codeExpr is Ast.Expression) {
return new Ast.ExpressionStatement { Expression = (Ast.Expression)codeExpr };
} else if (codeExpr is Ast.Statement) {
return (Ast.Statement)codeExpr;
} else {
throw new Exception();
List<Ast.Expression> args = TransformExpressionArguments(expr);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
switch(expr.OpCode.Code) {
case Code.Brfalse: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case Code.Brtrue: return arg1;
case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
default: throw new Exception("Bad opcode");
}
}
Ast.Expression MakeBranchCondition(Branch branch)
{
return MakeBranchCondition_Internal(branch);
}
Ast.Expression MakeBranchCondition_Internal(Branch branch)
{
if (branch is SimpleBranch) {
List<Ast.Expression> args = TransformExpressionArguments((ILExpression)((SimpleBranch)branch).BasicBlock.Body[0]);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
switch(((ILExpression)((SimpleBranch)branch).BasicBlock.Body[0]).OpCode.Code) {
case Code.Brfalse: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case Code.Brtrue: return arg1;
case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
case Code.Leave: return new Ast.PrimitiveExpression(true);
default: throw new Exception("Bad opcode");
}
/*
} else if (branch is ShortCircuitBranch) {
ShortCircuitBranch scBranch = (ShortCircuitBranch)branch;
switch(scBranch.Operator) {
@ -325,6 +248,7 @@ namespace Decompiler @@ -325,6 +248,7 @@ namespace Decompiler
} else {
throw new Exception("Bad type");
}
*/
}
static object TransformByteCode(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
@ -379,9 +303,10 @@ namespace Decompiler @@ -379,9 +303,10 @@ namespace Decompiler
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;
Ast.Statement branchCommand = null;
BlockStatement branchCommand = null;
if (byteCode.Operand is ILLabel) {
branchCommand = new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
branchCommand = new BlockStatement();
branchCommand.AddStatement(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name));
}
switch(opCode.Code) {
@ -449,7 +374,7 @@ namespace Decompiler @@ -449,7 +374,7 @@ namespace Decompiler
throw new NotImplementedException();
#endregion
#region Branching
case Code.Br: return branchCommand;
case Code.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1), 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);

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

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

5
ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs

@ -158,6 +158,11 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -158,6 +158,11 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
/// </summary>
public readonly List<ControlFlowEdge> Outgoing = new List<ControlFlowEdge>();
/// <summary>
/// Any user data
/// </summary>
public object UserData;
internal ControlFlowNode(int blockIndex, int offset, ControlFlowNodeType nodeType)
{
this.BlockIndex = blockIndex;

240
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -1,124 +1,118 @@ @@ -1,124 +1,118 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{984CC812-9470-4A13-AFF9-CC44068D666C}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Library</OutputType>
<RootNamespace>ICSharpCode.Decompiler</RootNamespace>
<AssemblyName>ICSharpCode.Decompiler</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Ast\AstBuilder.cs" />
<Compile Include="Ast\AstMetodBodyBuilder.cs" />
<Compile Include="Ast\CommentStatement.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\Transforms\Idioms.cs" />
<Compile Include="Ast\Transforms\PushNegation.cs" />
<Compile Include="Ast\Transforms\RemoveDeadLabels.cs" />
<Compile Include="Ast\Transforms\RemoveEmptyElseBody.cs" />
<Compile Include="Ast\Transforms\RemoveGotos.cs" />
<Compile Include="Ast\Transforms\RestoreLoop.cs" />
<Compile Include="Ast\Transforms\SimplifyTypeReferences.cs" />
<Compile Include="CecilExtensions.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" />
<Compile Include="Disassembler\ILStructure.cs" />
<Compile Include="Disassembler\MethodBodyDisassembler.cs" />
<Compile Include="Disassembler\ReflectionDisassembler.cs" />
<Compile Include="FlowAnalysis\ControlFlowEdge.cs" />
<Compile Include="FlowAnalysis\ControlFlowGraph.cs" />
<Compile Include="FlowAnalysis\ControlFlowGraphBuilder.cs" />
<Compile Include="FlowAnalysis\ControlFlowNode.cs" />
<Compile Include="FlowAnalysis\ControlStructureDetector.cs" />
<Compile Include="FlowAnalysis\OpCodeInfo.cs" />
<Compile Include="FlowAnalysis\SimplifyByRefCalls.cs" />
<Compile Include="FlowAnalysis\SsaBlock.cs" />
<Compile Include="FlowAnalysis\SsaForm.cs" />
<Compile Include="FlowAnalysis\SsaFormBuilder.cs" />
<Compile Include="FlowAnalysis\SsaInstruction.cs" />
<Compile Include="FlowAnalysis\SsaOptimization.cs" />
<Compile Include="FlowAnalysis\SsaVariable.cs" />
<Compile Include="FlowAnalysis\TransformToSsa.cs" />
<Compile Include="GraphVizGraph.cs" />
<Compile Include="ILAst\ControlFlow\Node-Optimize.cs" />
<Compile Include="ILAst\ControlFlow\Node-Structure.cs" />
<Compile Include="ILAst\ControlFlow\Node-Transforms.cs" />
<Compile Include="ILAst\ControlFlow\NodeCollection.cs" />
<Compile Include="ILAst\ControlFlow\Nodes.cs" />
<Compile Include="ILAst\ILAstBuilder.cs" />
<Compile Include="ILAst\ILAstTypes.cs" />
<Compile Include="ITextOutput.cs" />
<Compile Include="Mono.Cecil.Rocks\Constants.cs" />
<Compile Include="Mono.Cecil.Rocks\MethodBodyRocks.cs" />
<Compile Include="Mono.Cecil.Rocks\MyRocks.cs" />
<Compile Include="Options.cs" />
<Compile Include="PlainTextOutput.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<None Include="Properties\AssemblyInfo.template.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
</ProjectReference>
<ProjectReference Include="..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Ast" />
<Folder Include="Ast\Transforms" />
<Folder Include="Disassembler" />
<Folder Include="ILAst" />
<Folder Include="ILAst\ControlFlow" />
<Folder Include="Mono.Cecil.Rocks" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Target Name="BeforeBuild">
<MSBuild Projects="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\UpdateAssemblyInfo.csproj" Targets="Build" Properties="Configuration=Debug" />
<Exec WorkingDirectory="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\bin\Debug" Command="UpdateAssemblyInfo.exe --branchname $(BranchName)" Timeout="60000" Condition=" '$(BranchName)' != '' " />
<Exec WorkingDirectory="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\bin\Debug" Command="UpdateAssemblyInfo.exe" Timeout="60000" Condition=" '$(BranchName)' == '' " />
</Target>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{984CC812-9470-4A13-AFF9-CC44068D666C}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Library</OutputType>
<RootNamespace>ICSharpCode.Decompiler</RootNamespace>
<AssemblyName>ICSharpCode.Decompiler</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Ast\AstBuilder.cs" />
<Compile Include="Ast\AstMetodBodyBuilder.cs" />
<Compile Include="Ast\CommentStatement.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\Transforms\Idioms.cs" />
<Compile Include="Ast\Transforms\PushNegation.cs" />
<Compile Include="Ast\Transforms\RemoveEmptyElseBody.cs" />
<Compile Include="Ast\Transforms\RemoveGotos.cs" />
<Compile Include="Ast\Transforms\RestoreLoop.cs" />
<Compile Include="Ast\Transforms\SimplifyTypeReferences.cs" />
<Compile Include="CecilExtensions.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" />
<Compile Include="Disassembler\ILStructure.cs" />
<Compile Include="Disassembler\MethodBodyDisassembler.cs" />
<Compile Include="Disassembler\ReflectionDisassembler.cs" />
<Compile Include="FlowAnalysis\ControlFlowEdge.cs" />
<Compile Include="FlowAnalysis\ControlFlowGraph.cs" />
<Compile Include="FlowAnalysis\ControlFlowGraphBuilder.cs" />
<Compile Include="FlowAnalysis\ControlFlowNode.cs" />
<Compile Include="FlowAnalysis\ControlStructureDetector.cs" />
<Compile Include="FlowAnalysis\OpCodeInfo.cs" />
<Compile Include="FlowAnalysis\SimplifyByRefCalls.cs" />
<Compile Include="FlowAnalysis\SsaBlock.cs" />
<Compile Include="FlowAnalysis\SsaForm.cs" />
<Compile Include="FlowAnalysis\SsaFormBuilder.cs" />
<Compile Include="FlowAnalysis\SsaInstruction.cs" />
<Compile Include="FlowAnalysis\SsaOptimization.cs" />
<Compile Include="FlowAnalysis\SsaVariable.cs" />
<Compile Include="FlowAnalysis\TransformToSsa.cs" />
<Compile Include="GraphVizGraph.cs" />
<Compile Include="ILAst\ILAstBuilder.cs" />
<Compile Include="ILAst\ILAstOptimizer.cs" />
<Compile Include="ILAst\ILAstTypes.cs" />
<Compile Include="ITextOutput.cs" />
<Compile Include="Mono.Cecil.Rocks\Constants.cs" />
<Compile Include="Mono.Cecil.Rocks\MethodBodyRocks.cs" />
<Compile Include="Mono.Cecil.Rocks\MyRocks.cs" />
<Compile Include="Options.cs" />
<Compile Include="PlainTextOutput.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<None Include="Properties\AssemblyInfo.template.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
</ProjectReference>
<ProjectReference Include="..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Ast" />
<Folder Include="Ast\Transforms" />
<Folder Include="Disassembler" />
<Folder Include="ILAst" />
<Folder Include="Mono.Cecil.Rocks" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Target Name="BeforeBuild">
<MSBuild Projects="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\UpdateAssemblyInfo.csproj" Targets="Build" Properties="Configuration=Debug" />
<Exec WorkingDirectory="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\bin\Debug" Command="UpdateAssemblyInfo.exe --branchname $(BranchName)" Timeout="60000" Condition=" '$(BranchName)' != '' " />
<Exec WorkingDirectory="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\bin\Debug" Command="UpdateAssemblyInfo.exe" Timeout="60000" Condition=" '$(BranchName)' == '' " />
</Target>
</Project>

188
ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Optimize.cs

@ -1,188 +0,0 @@ @@ -1,188 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Decompiler.ControlFlow
{
public abstract partial class Node
{
public void Optimize()
{
if (Options.ReduceLoops) {
OptimizeLoops();
}
if (Options.ReduceConditonals) {
OptimizeShortCircuits();
OptimizeConditions();
}
}
public void OptimizeLoops()
{
Reset:
foreach(Node child in this.Childs) {
if (child.Predecessors.Count == 1) {
Node predecessor = child.Predecessors[0];
Node mergedNode;
if (child.Successors.Contains(predecessor)) {
mergedNode = MergeChilds<Loop>(predecessor, child);
} else {
mergedNode = MergeChilds<AcyclicGraph>(predecessor, child);
}
mergedNode.FalttenAcyclicChilds();
goto Reset;
}
}
// If the result is single acyclic node, eliminate it
if (this.Childs.Count == 1 && this.HeadChild is AcyclicGraph) {
Node headChild = this.HeadChild;
this.Childs.Remove(this.HeadChild);
headChild.Childs.MoveTo(this);
}
}
NodeCollection GetReachableNodes()
{
NodeCollection reachableNodes = new NodeCollection();
reachableNodes.Add(this);
for(int i = 0; i < reachableNodes.Count; i++) {
foreach(Node alsoReachable in reachableNodes[i].Successors) {
// Do not go though the head child
if (alsoReachable != this.Parent.HeadChild) {
reachableNodes.Add(alsoReachable);
}
}
}
return reachableNodes;
}
public void OptimizeShortCircuits()
{
foreach(Node child in this.Childs) {
child.OptimizeShortCircuits();
}
Reset:
foreach(Node child in this.Childs) {
if (TryOptimizeShortCircuit(child)) {
goto Reset;
}
}
}
public static bool TryOptimizeShortCircuit(Node head)
{
if ((head is BasicBlock) &&
(head as BasicBlock).BranchBasicBlock != null &&
(head as BasicBlock).FallThroughBasicBlock != null) {
head.Parent.MergeChilds<SimpleBranch>(head);
return true;
}
Branch top = head as Branch;
if (top == null) return false;
Branch left = head.FloatUpToNeighbours(top.TrueSuccessor) as Branch;
Branch right = head.FloatUpToNeighbours(top.FalseSuccessor) as Branch;
// A & B
if (left != null &&
left.Predecessors.Count == 1 &&
left.FalseSuccessor == top.FalseSuccessor) {
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, left);
scBranch.Operator = ShortCircuitOperator.LeftAndRight;
return true;
}
// ~A | B
if (left != null &&
left.Predecessors.Count == 1 &&
left.TrueSuccessor == top.FalseSuccessor) {
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, left);
scBranch.Operator = ShortCircuitOperator.NotLeftOrRight;
return true;
}
// A | B
if (right != null &&
right.Predecessors.Count == 1 &&
right.TrueSuccessor == top.TrueSuccessor) {
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, right);
scBranch.Operator = ShortCircuitOperator.LeftOrRight;
return true;
}
// ~A & B
if (right != null &&
right.Predecessors.Count == 1 &&
right.FalseSuccessor == top.TrueSuccessor) {
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, right);
scBranch.Operator = ShortCircuitOperator.NotLeftAndRight;
return true;
}
return false;
}
public void OptimizeConditions()
{
foreach(Node child in this.Childs) {
child.OptimizeConditions();
}
Node conditionNode = this.HeadChild;
while(conditionNode != null) {
// Keep looking for some conditional block
if (conditionNode is Branch) {
// Found start of conditional
OptimizeIf((Branch)conditionNode);
// Restart
conditionNode = this.HeadChild;
continue;
} else if (conditionNode.Successors.Count > 0) {
// Keep looking down
conditionNode = conditionNode.Successors[0];
if (conditionNode == this.HeadChild) {
return;
}
continue; // Next
} else {
return; // End of block
}
}
}
public static void OptimizeIf(Branch condition)
{
Node trueStart = condition.FloatUpToNeighbours(condition.TrueSuccessor);
Node falseStart = condition.FloatUpToNeighbours(condition.FalseSuccessor);
NodeCollection trueReachable = trueStart != null ? trueStart.GetReachableNodes() : NodeCollection.Empty;
NodeCollection falseReachable = falseStart != null ? falseStart.GetReachableNodes() : NodeCollection.Empty;
NodeCollection commonReachable = NodeCollection.Intersect(trueReachable, falseReachable);
NodeCollection trueNodes = trueReachable.Clone();
trueNodes.RemoveRange(commonReachable);
NodeCollection falseNodes = falseReachable.Clone();
falseNodes.RemoveRange(commonReachable);
// Replace the basic block with condition node
Node conditionParent = condition.Parent;
int conditionIndex = condition.Index;
ConditionalNode conditionalNode = new ConditionalNode(condition);
conditionalNode.MoveTo(conditionParent, conditionIndex);
// If there are no common nodes, let the 'true' block be the default
if (commonReachable.Count > 0) {
trueNodes.MoveTo(conditionalNode.TrueBody);
}
falseNodes.MoveTo(conditionalNode.FalseBody);
// Optimize the created subtrees
conditionalNode.TrueBody.OptimizeConditions();
conditionalNode.FalseBody.OptimizeConditions();
}
}
}

233
ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Structure.cs

@ -1,233 +0,0 @@ @@ -1,233 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Decompiler.ControlFlow
{
public abstract partial class Node
{
public static int NextNodeID = 1;
int id;
string label;
Node parent;
NodeCollection childs = new NodeCollection();
// Structural and linking cache
NodeCollection basicBlocks_cache = null;
NodeCollection predecessors_cache = null;
NodeCollection successors_cache = null;
public int ID {
get { return id; }
}
public string Label {
get { return label; }
}
public Node Parent {
get { return parent; }
}
public Node HeadChild {
get {
if (this.Childs.Count > 0) {
return this.Childs[0];
} else {
return null;
}
}
}
public NodeCollection Childs {
get {
return childs;
}
}
/// <summary> All basic blocks within the scope of this node (inclusive) </summary>
public NodeCollection BasicBlocks {
get {
if (basicBlocks_cache == null) {
NodeCollection basicBlocks = new NodeCollection();
if (this is BasicBlock) {
basicBlocks.Add(this);
}
foreach(Node child in this.Childs) {
basicBlocks.AddRange(child.BasicBlocks);
}
basicBlocks_cache = basicBlocks;
}
return basicBlocks_cache;
}
}
NodeCollection FloatUpToNeighbours(IEnumerable<BasicBlock> basicBlocks)
{
NodeCollection neighbours = new NodeCollection();
if (this.Parent != null) {
foreach(BasicBlock basicBlock in basicBlocks) {
Node targetNode = FloatUpToNeighbours(basicBlock);
// The target is outside the scope of the parent node
if (targetNode == null) continue;
// This child is a loop
if (targetNode == this) continue;
// We found a target in our scope
neighbours.Add(targetNode);
}
}
return neighbours;
}
Node FloatUpToNeighbours(BasicBlock basicBlock)
{
// Find neighbour coresponding to the basickBlock
Node targetNode = basicBlock;
while(targetNode != null && targetNode.Parent != this.Parent) {
targetNode = targetNode.Parent;
}
return targetNode;
}
public NodeCollection Predecessors {
get {
if (predecessors_cache == null) {
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>();
foreach(BasicBlock basicBlock in this.BasicBlocks) {
foreach(BasicBlock basicBlockPredecessor in basicBlock.BasicBlockPredecessors) {
basicBlockPredecessors.Add(basicBlockPredecessor);
}
}
predecessors_cache = FloatUpToNeighbours(basicBlockPredecessors);
}
return predecessors_cache;
}
}
public NodeCollection Successors {
get {
if (successors_cache == null) {
List<BasicBlock> basicBlockSuccessors = new List<BasicBlock>();
foreach(BasicBlock basicBlock in this.BasicBlocks) {
foreach(BasicBlock basicBlockSuccessor in basicBlock.BasicBlockSuccessors) {
basicBlockSuccessors.Add(basicBlockSuccessor);
}
}
successors_cache = FloatUpToNeighbours(basicBlockSuccessors);
}
return successors_cache;
}
}
int Index {
get {
if (this.Parent == null) throw new Exception("Does not have a parent");
return this.Parent.Childs.IndexOf(this);
}
}
public Node NextNode {
get {
int index = this.Index + 1;
if (0 <= index && index < this.Parent.Childs.Count) {
return this.Parent.Childs[index];
} else {
return null;
}
}
}
public string Description {
get {
return ToString();
}
}
protected Node()
{
this.id = NextNodeID++;
this.label = 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");
}
e.Node.parent = this;
NotifyChildsChanged();
};
this.Childs.Removed += delegate(object sender, NodeEventArgs e) {
e.Node.parent = null;
NotifyChildsChanged();
};
}
void NotifyChildsChanged()
{
this.basicBlocks_cache = null;
foreach(Node child in this.Childs) {
child.predecessors_cache = null;
child.successors_cache = null;
}
if (this.Parent != null) {
this.Parent.NotifyChildsChanged();
}
}
public override string ToString()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append(this.GetType().Name);
sb.Append(" ");
sb.Append(ID);
sb.Append(" ");
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.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.Parent != null) {
sb.Append("Parent:");
sb.Append(this.Parent.ID);
sb.Append(" ");
}
if (sb[sb.Length - 1] == '(') {
sb.Length -= 1;
} else if (sb[sb.Length - 1] == ' ') {
sb.Length -= 1;
sb.Append(")");
}
return sb.ToString();
}
}
}

60
ICSharpCode.Decompiler/ILAst/ControlFlow/Node-Transforms.cs

@ -1,60 +0,0 @@ @@ -1,60 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Decompiler.ControlFlow
{
public abstract partial class Node
{
public void Remove()
{
if (this.Parent != null) {
this.Parent.Childs.Remove(this);
}
}
public void MoveTo(Node newNode)
{
MoveTo(newNode, newNode.Childs.Count);
}
public void MoveTo(Node newNode, int index)
{
this.Remove();
newNode.Childs.Insert(index, this);
}
T MergeChilds<T>(params Node[] nodes) where T: Node, new()
{
foreach(Node node in nodes) {
if (node == null) throw new ArgumentNullException("nodes");
if (node.Parent != this) throw new ArgumentException("The node is not my child");
}
if (nodes.Length == 0) throw new ArgumentException("At least one node must be specified");
T mergedNode = new T();
// Add the merged node
int headIndex = this.Childs.IndexOf(nodes[0]);
this.Childs.Insert(headIndex, mergedNode);
foreach(Node node in nodes) {
node.MoveTo(mergedNode);
}
return mergedNode;
}
public void FalttenAcyclicChilds()
{
Reset:
foreach(Node child in this.Childs) {
if (child is AcyclicGraph) {
child.Childs.MoveTo(this, child.Index);
child.Remove();
goto Reset;
}
}
}
}
}

130
ICSharpCode.Decompiler/ILAst/ControlFlow/NodeCollection.cs

@ -1,130 +0,0 @@ @@ -1,130 +0,0 @@
using System;
using System.Collections.Generic;
namespace Decompiler.ControlFlow
{
public class NodeEventArgs: EventArgs
{
Node node;
public Node Node {
get { return node; }
}
public NodeEventArgs(Node node)
{
this.node = node;
}
}
public class NodeCollection: System.Collections.ObjectModel.Collection<Node>
{
public static NodeCollection Empty = new NodeCollection();
public event EventHandler<NodeEventArgs> Added;
public event EventHandler<NodeEventArgs> Removed;
protected virtual void OnAdded(Node node)
{
if (Added != null) {
Added(this, new NodeEventArgs(node));
}
}
protected virtual void OnRemoved(Node node)
{
if (Removed != null) {
Removed(this, new NodeEventArgs(node));
}
}
protected override void ClearItems()
{
while(this.Count > 0) {
this.RemoveAt(this.Count - 1);
}
}
protected override void InsertItem(int index, Node item)
{
if (!this.Contains(item)) {
base.InsertItem(index, item);
}
OnAdded(item);
}
protected override void RemoveItem(int index)
{
Node node = this[index];
base.RemoveItem(index);
OnRemoved(node);
}
protected override void SetItem(int index, Node item)
{
this.RemoveAt(index);
this.Insert(index, item);
}
public void AddRange(IEnumerable<Node> items)
{
foreach(Node item in items) {
this.Add(item);
}
}
public void RemoveRange(IEnumerable<Node> items)
{
foreach(Node item in items) {
this.Remove(item);
}
}
public void MoveTo(Node newNode)
{
foreach(Node child in this.Clone()) {
child.MoveTo(newNode);
}
}
public void MoveTo(Node newNode, int index)
{
foreach(Node child in this.Clone()) {
child.MoveTo(newNode, index);
index++;
}
}
public NodeCollection()
{
}
public NodeCollection(IEnumerable<Node> items)
{
this.AddRange(items);
}
public NodeCollection Clone()
{
return new NodeCollection(this);
}
public static NodeCollection Intersect(NodeCollection collectionA, NodeCollection collectionB)
{
NodeCollection result = new NodeCollection();
foreach(Node a in collectionA) {
if (collectionB.Contains(a)) {
result.Add(a);
}
}
return result;
}
public override string ToString()
{
return string.Format("{0} Count = {1}", typeof(NodeCollection).Name, this.Count);
}
}
}

254
ICSharpCode.Decompiler/ILAst/ControlFlow/Nodes.cs

@ -1,254 +0,0 @@ @@ -1,254 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Decompiler.Rocks;
namespace Decompiler.ControlFlow
{
public class BasicBlock: Node
{
List<ILNode> body = new List<ILNode>();
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>();
BasicBlock fallThroughBasicBlock;
BasicBlock branchBasicBlock;
public List<ILNode> Body {
get { return body; }
}
public List<BasicBlock> BasicBlockPredecessors {
get { return basicBlockPredecessors; }
}
public BasicBlock FallThroughBasicBlock {
get { return fallThroughBasicBlock; }
set { fallThroughBasicBlock = value; }
}
public BasicBlock BranchBasicBlock {
get { return branchBasicBlock; }
set { branchBasicBlock = value; }
}
public IEnumerable<BasicBlock> BasicBlockSuccessors {
get {
if (this.FallThroughBasicBlock != null) {
yield return this.FallThroughBasicBlock;
}
if (this.BranchBasicBlock != null) {
yield return this.BranchBasicBlock;
}
}
}
}
public enum ShortCircuitOperator {
LeftAndRight,
LeftOrRight,
NotLeftAndRight,
NotLeftOrRight,
}
public abstract class Branch: Node
{
public abstract BasicBlock FirstBasicBlock { get; }
public abstract BasicBlock TrueSuccessor { get; }
public abstract BasicBlock FalseSuccessor { get; }
}
public class SimpleBranch: Branch
{
public override BasicBlock FirstBasicBlock {
get {
return this.BasicBlock;
}
}
public BasicBlock BasicBlock {
get { return (BasicBlock)this.Childs[0]; }
}
public override BasicBlock TrueSuccessor {
get { return this.BasicBlock.BranchBasicBlock; }
}
public override BasicBlock FalseSuccessor {
get { return this.BasicBlock.FallThroughBasicBlock; }
}
}
public class ShortCircuitBranch: Branch
{
ShortCircuitOperator @operator;
public override BasicBlock FirstBasicBlock {
get {
return this.Left.FirstBasicBlock;
}
}
public Branch Left {
get { return (Branch)this.Childs[0];; }
}
public Branch Right {
get { return (Branch)this.Childs[1]; }
}
public ShortCircuitOperator Operator {
get { return @operator; }
set { @operator = value; }
}
public override BasicBlock TrueSuccessor {
get { return this.Right.TrueSuccessor; }
}
public override BasicBlock FalseSuccessor {
get { return this.Right.FalseSuccessor; }
}
}
public class MethodBodyGraph: Node
{
BasicBlock methodEntry;
public BasicBlock MethodEntry {
get { return methodEntry; }
}
Dictionary<ILLabel, BasicBlock> labelToBasicBlock = new Dictionary<ILLabel, BasicBlock>();
public MethodBodyGraph(List<ILNode> ast)
{
if (ast.Count == 0) throw new ArgumentException("Count == 0", "ast");
this.Childs.AddRange(SplitToBasicBlocks(ast));
// Add branch links to BasicBlocks
foreach(BasicBlock basicBlock in this.BasicBlocks) {
foreach(ILNode node in basicBlock.Body) {
if (node is ILExpression) {
ILExpression expr = (ILExpression)node;
if (expr.Operand is ILLabel) {
BasicBlock target = labelToBasicBlock[(ILLabel)expr.Operand];
basicBlock.BranchBasicBlock = target;
target.BasicBlockPredecessors.Add(basicBlock);
}
// TODO: Switch
}
}
}
}
public List<Node> SplitToBasicBlocks(List<ILNode> ast)
{
if (ast.Count == 0) return new List<Node>();
List<Node> nodes = new List<Node>();
BasicBlock basicBlock = null;
for(int i = 0; i < ast.Count; i++) {
if (i == 0 ||
ast[i] is ILLabel ||
ast[i - 1] is ILTryCatchBlock ||
ast[i] is ILTryCatchBlock ||
(ast[i - 1] is ILExpression) && ((ILExpression)ast[i - 1]).OpCode.IsBranch() ||
(ast[i] is ILExpression) && ((ILExpression)ast[i]).OpCode.IsBranch())
{
BasicBlock oldBB = basicBlock;
basicBlock = new BasicBlock();
if (methodEntry == null) methodEntry = basicBlock;
nodes.Add(basicBlock);
// Links
if (oldBB != null && ast[i - 1] is ILExpression && ((ILExpression)ast[i - 1]).OpCode.CanFallThough()) {
oldBB.FallThroughBasicBlock = basicBlock;
basicBlock.BasicBlockPredecessors.Add(oldBB);
}
}
if (ast[i] is ILTryCatchBlock) {
basicBlock.Childs.Add(ConvertTryCatch((ILTryCatchBlock)ast[i]));
} else {
basicBlock.Body.Add(ast[i]);
}
if (ast[i] is ILLabel) {
labelToBasicBlock[(ILLabel)ast[i]] = basicBlock;
}
}
return nodes;
}
public TryCatchNode ConvertTryCatch(ILTryCatchBlock ilTryCatch)
{
TryCatchNode tryCatch = new TryCatchNode();
Block tryBlock = new Block();
tryBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.TryBlock));
tryBlock.MoveTo(tryCatch);
Block finallyBlock = new Block();
if (ilTryCatch.FinallyBlock != null) {
finallyBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.FinallyBlock));
}
finallyBlock.MoveTo(tryCatch);
foreach(ILTryCatchBlock.CatchBlock cb in ilTryCatch.CatchBlocks) {
tryCatch.Types.Add(cb.ExceptionType);
Block catchBlock = new Block();
catchBlock.Childs.AddRange(SplitToBasicBlocks(cb.Body));
catchBlock.MoveTo(tryCatch);
}
return tryCatch;
}
}
public class TryCatchNode: Node
{
public List<TypeReference> Types = new List<TypeReference>();
}
public class AcyclicGraph: Node
{
}
public class Loop: Node
{
}
public class Block: Node
{
}
public class ConditionalNode: Node
{
Branch condition;
Block trueBody = new Block();
Block falseBody = new Block();
public Branch Condition {
get { return condition; }
}
public Block TrueBody {
get { return trueBody; }
}
public Block FalseBody {
get { return falseBody; }
}
public ConditionalNode(Branch condition)
{
this.condition = condition;
condition.MoveTo(this);
trueBody.MoveTo(this);
falseBody.MoveTo(this);
}
}
}

4
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -312,7 +312,7 @@ namespace Decompiler @@ -312,7 +312,7 @@ namespace Decompiler
List<ExceptionHandler> nestedEHs = ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)).ToList();
int tryEndIdx;
for (tryEndIdx = 0; tryEndIdx < body.Count && body[tryEndIdx].Offset != tryEnd; tryEndIdx++);
tryCatchBlock.TryBlock = ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs);
tryCatchBlock.TryBlock = new ILBlock(ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs));
}
// Cut all handlers
@ -331,7 +331,7 @@ namespace Decompiler @@ -331,7 +331,7 @@ namespace Decompiler
Body = handlerAst
});
} else if (eh.HandlerType == ExceptionHandlerType.Finally) {
tryCatchBlock.FinallyBlock = handlerAst;
tryCatchBlock.FinallyBlock = new ILBlock(handlerAst);
} else {
// TODO
}

456
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -0,0 +1,456 @@ @@ -0,0 +1,456 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.FlowAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Decompiler.Rocks;
namespace Decompiler.ControlFlow
{
public class ILAstOptimizer
{
Dictionary<ILLabel, ControlFlowNode> labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
public void Optimize(ref List<ILNode> ast)
{
OptimizeRecursive(ref ast);
// Provide a container for the algorithms below
ILBlock astBlock = new ILBlock(ast);
OrderNodes(astBlock);
FlattenNestedMovableBlocks(astBlock);
SimpleGotoRemoval(astBlock);
RemoveDeadLabels(astBlock);
ast = astBlock.Body;
}
void OptimizeRecursive(ref List<ILNode> ast)
{
ILLabel entryLabel;
List<ILTryCatchBlock> tryCatchBlocks = ast.OfType<ILTryCatchBlock>().ToList();
ControlFlowGraph graph;
ast = SplitToMovableBlocks(ast, out entryLabel);
graph = BuildGraph(ast, entryLabel);
graph.ComputeDominance();
graph.ComputeDominanceFrontier();
ast = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint);
graph = BuildGraph(ast, entryLabel);
graph.ComputeDominance();
graph.ComputeDominanceFrontier();
ast = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint);
// Recursively optimze try-cath blocks
foreach(ILTryCatchBlock tryCatchBlock in tryCatchBlocks) {
Optimize(ref tryCatchBlock.TryBlock.Body);
foreach(ILTryCatchBlock.CatchBlock catchBlock in tryCatchBlock.CatchBlocks) {
Optimize(ref catchBlock.Body);
}
Optimize(ref tryCatchBlock.FinallyBlock.Body);
}
ast.Insert(0, new ILExpression(OpCodes.Br, entryLabel));
}
class ILMoveableBlock: ILBlock
{
public int OriginalOrder;
}
int nextBlockIndex = 0;
/// <summary>
/// Group input into a set of blocks that can be later arbitraliby schufled.
/// The method adds necessary branches to make control flow between blocks
/// explicit and thus order independent.
/// </summary>
List<ILNode> SplitToMovableBlocks(List<ILNode> ast, out ILLabel entryLabel)
{
List<ILNode> blocks = new List<ILNode>();
ILMoveableBlock block = new ILMoveableBlock() { OriginalOrder = (nextBlockIndex++) };
blocks.Add(block);
entryLabel = new ILLabel() { Name = "Block_" + block.OriginalOrder };
block.Body.Add(entryLabel);
if (ast.Count == 0)
return blocks;
block.Body.Add(ast[0]);
for (int i = 1; i < ast.Count; i++) {
ILNode lastNode = ast[i - 1];
ILNode currNode = ast[i];
// Insert split
if ((currNode is ILLabel && !(lastNode is ILLabel)) ||
lastNode is ILTryCatchBlock ||
currNode is ILTryCatchBlock ||
(lastNode is ILExpression) && ((ILExpression)lastNode).OpCode.IsBranch() ||
(currNode is ILExpression) && ((ILExpression)currNode).OpCode.IsBranch())
{
ILBlock lastBlock = block;
block = new ILMoveableBlock() { OriginalOrder = (nextBlockIndex++) };
blocks.Add(block);
// Explicit branch from one block to other
// (unless the last expression was unconditional branch)
if (!(lastNode is ILExpression) || ((ILExpression)lastNode).OpCode.CanFallThough()) {
ILLabel blockLabel = new ILLabel() { Name = "Block_" + block.OriginalOrder };
lastBlock.Body.Add(new ILExpression(OpCodes.Br, blockLabel));
block.Body.Add(blockLabel);
}
}
block.Body.Add(currNode);
}
return blocks;
}
ControlFlowGraph BuildGraph(List<ILNode> nodes, ILLabel entryLabel)
{
int index = 0;
List<ControlFlowNode> cfNodes = new List<ControlFlowNode>();
ControlFlowNode entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint);
cfNodes.Add(entryPoint);
ControlFlowNode regularExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.RegularExit);
cfNodes.Add(regularExit);
ControlFlowNode exceptionalExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.ExceptionalExit);
cfNodes.Add(exceptionalExit);
// Create graph nodes
labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
Dictionary<ILNode, ControlFlowNode> astNodeToCfNode = new Dictionary<ILNode, ControlFlowNode>();
foreach(ILNode node in nodes) {
ControlFlowNode cfNode = new ControlFlowNode(index++, -1, ControlFlowNodeType.Normal);
cfNodes.Add(cfNode);
astNodeToCfNode[node] = cfNode;
cfNode.UserData = node;
// Find all contained labels
foreach(ILLabel label in node.GetSelfAndChildrenRecursive<ILLabel>()) {
labelToCfNode[label] = cfNode;
}
}
// Entry endge
ControlFlowNode entryNode = labelToCfNode[entryLabel];
ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal);
entryPoint.Outgoing.Add(entryEdge);
entryNode.Incoming.Add(entryEdge);
// Create edges
foreach(ILNode node in nodes) {
ControlFlowNode source = astNodeToCfNode[node];
// Find all branches
foreach(ILExpression child in node.GetSelfAndChildrenRecursive<ILExpression>()) {
IEnumerable<ILLabel> targets = child.GetBranchTargets();
if (targets != null) {
foreach(ILLabel target in targets) {
ControlFlowNode destination;
// Labels which are out of out scope will not be int the collection
if (labelToCfNode.TryGetValue(target, out destination) && destination != source) {
ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);
source.Outgoing.Add(edge);
destination.Incoming.Add(edge);
}
}
}
}
}
return new ControlFlowGraph(cfNodes.ToArray());
}
static List<ILNode> FindLoops(HashSet<ControlFlowNode> nodes, ControlFlowNode entryPoint)
{
List<ILNode> result = new List<ILNode>();
Queue<ControlFlowNode> agenda = new Queue<ControlFlowNode>();
agenda.Enqueue(entryPoint);
while(agenda.Count > 0) {
ControlFlowNode node = agenda.Dequeue();
if (nodes.Contains(node)
&& node.DominanceFrontier.Contains(node)
&& node != entryPoint)
{
HashSet<ControlFlowNode> loopContents = new HashSet<ControlFlowNode>();
FindLoopContents(nodes, loopContents, node, node);
// Move the content into loop block
nodes.ExceptWith(loopContents);
result.Add(new ILLoop() { ContentBlock = new ILBlock(FindLoops(loopContents, node)) });
}
// Using the dominator tree should ensure we find the the widest loop first
foreach(var child in node.DominatorTreeChildren) {
agenda.Enqueue(child);
}
}
// Add whatever is left
foreach(var node in nodes) {
result.Add((ILNode)node.UserData);
}
return result;
}
static void FindLoopContents(HashSet<ControlFlowNode> nodes, HashSet<ControlFlowNode> loopContents, ControlFlowNode loopHead, ControlFlowNode addNode)
{
if (nodes.Contains(addNode) && loopHead.Dominates(addNode) && loopContents.Add(addNode)) {
foreach (var edge in addNode.Incoming) {
FindLoopContents(nodes, loopContents, loopHead, edge.Source);
}
}
}
List<ILNode> FindConditions(HashSet<ControlFlowNode> nodes, ControlFlowNode entryNode)
{
List<ILNode> result = new List<ILNode>();
Queue<ControlFlowNode> agenda = new Queue<ControlFlowNode>();
agenda.Enqueue(entryNode);
while(agenda.Count > 0) {
ControlFlowNode node = agenda.Dequeue();
ILMoveableBlock block = node.UserData as ILMoveableBlock;
// Find a block that represents a simple condition
if (nodes.Contains(node) && block != null && block.Body.Count == 3) {
ILLabel label = block.Body[0] as ILLabel;
ILExpression condBranch = block.Body[1] as ILExpression;
ILExpression statBranch = block.Body[2] as ILExpression;
if (label != null &&
condBranch != null && condBranch.Operand is ILLabel && condBranch.Arguments.Count > 0 &&
statBranch != null && statBranch.Operand is ILLabel && statBranch.Arguments.Count == 0)
{
ControlFlowNode condTarget;
ControlFlowNode statTarget;
if (labelToCfNode.TryGetValue((ILLabel)condBranch.Operand, out condTarget) &&
labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget))
{
ILCondition condition = new ILCondition() {
Condition = condBranch,
TrueTarget = (ILLabel)condBranch.Operand,
FalseTarget = (ILLabel)statBranch.Operand
};
// TODO: Use the labels to ensre correctness
// TODO: Ensure that the labels are considered live in dead label removal
// Replace the two branches with a conditional structure
block.Body.Remove(condBranch);
block.Body.Remove(statBranch);
block.Body.Add(condition);
result.Add(block);
// Pull in the conditional code
HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
frontiers.UnionWith(condTarget.DominanceFrontier);
frontiers.UnionWith(statTarget.DominanceFrontier);
if (!frontiers.Contains(condTarget)) {
HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget);
nodes.ExceptWith(content);
condition.TrueBlock = new ILBlock(FindConditions(content, condTarget));
}
if (!frontiers.Contains(statTarget)) {
HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, statTarget);
nodes.ExceptWith(content);
condition.FalseBlock = new ILBlock(FindConditions(content, statTarget));
}
nodes.Remove(node);
}
}
}
// Using the dominator tree should ensure we find the the widest loop first
foreach(var child in node.DominatorTreeChildren) {
agenda.Enqueue(child);
}
}
// Add whatever is left
foreach(var node in nodes) {
result.Add((ILNode)node.UserData);
}
return result;
}
static HashSet<ControlFlowNode> FindDominatedNodes(HashSet<ControlFlowNode> nodes, ControlFlowNode head)
{
var exitNodes = head.DominanceFrontier.SelectMany(n => n.Predecessors);
HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>(exitNodes);
HashSet<ControlFlowNode> result = new HashSet<ControlFlowNode>();
while(agenda.Count > 0) {
ControlFlowNode addNode = agenda.First();
agenda.Remove(addNode);
if (nodes.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) {
foreach (var predecessor in addNode.Predecessors) {
agenda.Add(predecessor);
}
}
}
result.Add(head);
return result;
}
/*
public enum ShortCircuitOperator
{
LeftAndRight,
LeftOrRight,
NotLeftAndRight,
NotLeftOrRight,
}
static bool TryOptimizeShortCircuit(Node head)
{
if ((head is BasicBlock) &&
(head as BasicBlock).BranchBasicBlock != null &&
(head as BasicBlock).FallThroughBasicBlock != null) {
head.Parent.MergeChilds<SimpleBranch>(head);
return true;
}
Branch top = head as Branch;
if (top == null) return false;
Branch left = head.FloatUpToNeighbours(top.TrueSuccessor) as Branch;
Branch right = head.FloatUpToNeighbours(top.FalseSuccessor) as Branch;
// A & B
if (left != null &&
left.Predecessors.Count == 1 &&
left.FalseSuccessor == top.FalseSuccessor) {
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, left);
scBranch.Operator = ShortCircuitOperator.LeftAndRight;
return true;
}
// ~A | B
if (left != null &&
left.Predecessors.Count == 1 &&
left.TrueSuccessor == top.FalseSuccessor) {
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, left);
scBranch.Operator = ShortCircuitOperator.NotLeftOrRight;
return true;
}
// A | B
if (right != null &&
right.Predecessors.Count == 1 &&
right.TrueSuccessor == top.TrueSuccessor) {
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, right);
scBranch.Operator = ShortCircuitOperator.LeftOrRight;
return true;
}
// ~A & B
if (right != null &&
right.Predecessors.Count == 1 &&
right.FalseSuccessor == top.TrueSuccessor) {
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, right);
scBranch.Operator = ShortCircuitOperator.NotLeftAndRight;
return true;
}
return false;
}
*/
void OrderNodes(ILBlock ast)
{
var blocks = ast.GetSelfAndChildrenRecursive<ILBlock>().ToList();
ILMoveableBlock first = new ILMoveableBlock() { OriginalOrder = -1 };
foreach(ILBlock block in blocks) {
block.Body = block.Body.OrderBy(n => (n.GetSelfAndChildrenRecursive<ILMoveableBlock>().FirstOrDefault() ?? first).OriginalOrder).ToList();
}
}
/// <summary>
/// Flattens all nested movable blocks, except the the top level 'node' argument
/// </summary>
void FlattenNestedMovableBlocks(ILNode node)
{
ILBlock block = node as ILBlock;
if (block != null) {
List<ILNode> flatBody = new List<ILNode>();
foreach (ILNode child in block.Body) {
FlattenNestedMovableBlocks(child);
if (child is ILMoveableBlock) {
flatBody.AddRange(((ILMoveableBlock)child).Body);
} else {
flatBody.Add(child);
}
}
block.Body = flatBody;
} else if (node is ILExpression) {
// Optimization - no need to check expressions
} else if (node != null) {
// Recursively find all ILBlocks
foreach(ILNode child in node.GetChildren()) {
FlattenNestedMovableBlocks(child);
}
}
}
void SimpleGotoRemoval(ILBlock ast)
{
var blocks = ast.GetSelfAndChildrenRecursive<ILBlock>().ToList();
foreach(ILBlock block in blocks) {
for (int i = 0; i < block.Body.Count; i++) {
ILExpression expr = block.Body[i] as ILExpression;
// Uncoditional branch
if (expr != null && (expr.OpCode == OpCodes.Br || expr.OpCode == OpCodes.Br_S)) {
// Check that branch is followed by its label (allow multiple labels)
for (int j = i + 1; j < block.Body.Count; j++) {
ILLabel label = block.Body[j] as ILLabel;
if (label == null)
break; // Can not optimize
if (expr.Operand == label) {
block.Body.RemoveAt(i);
break; // Branch removed
}
}
}
}
}
}
void RemoveDeadLabels(ILBlock ast)
{
HashSet<ILLabel> liveLabels = new HashSet<ILLabel>(ast.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.GetBranchTargets()));
var blocks = ast.GetSelfAndChildrenRecursive<ILBlock>().ToList();
foreach(ILBlock block in blocks) {
for (int i = 0; i < block.Body.Count;) {
ILLabel label = block.Body[i] as ILLabel;
if (label != null && !liveLabels.Contains(label)) {
block.Body.RemoveAt(i);
} else {
i++;
}
}
}
}
}
}

115
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -9,8 +9,61 @@ using Cecil = Mono.Cecil; @@ -9,8 +9,61 @@ using Cecil = Mono.Cecil;
namespace Decompiler
{
public class ILNode
public abstract class ILNode
{
public IEnumerable<T> GetSelfAndChildrenRecursive<T>() where T: ILNode
{
if (this is T)
yield return (T)this;
Stack<IEnumerator<ILNode>> stack = new Stack<IEnumerator<ILNode>>();
try {
stack.Push(GetChildren().GetEnumerator());
while (stack.Count > 0) {
while (stack.Peek().MoveNext()) {
ILNode element = stack.Peek().Current;
if (element != null) {
if (element is T)
yield return (T)element;
IEnumerable<ILNode> children = element.GetChildren();
if (children != null) {
stack.Push(children.GetEnumerator());
}
}
}
stack.Pop().Dispose();
}
} finally {
while (stack.Count > 0) {
stack.Pop().Dispose();
}
}
}
public virtual IEnumerable<ILNode> GetChildren()
{
yield break;
}
}
public class ILBlock: ILNode
{
public List<ILNode> Body;
public ILBlock(params ILNode[] body)
{
this.Body = new List<ILNode>(body);
}
public ILBlock(List<ILNode> body)
{
this.Body = body;
}
public override IEnumerable<ILNode> GetChildren()
{
return this.Body;
}
}
public class ILLabel: ILNode
@ -25,15 +78,23 @@ namespace Decompiler @@ -25,15 +78,23 @@ namespace Decompiler
public class ILTryCatchBlock: ILNode
{
public class CatchBlock
public class CatchBlock: ILBlock
{
public TypeReference ExceptionType;
public List<ILNode> Body;
}
public List<ILNode> TryBlock;
public ILBlock TryBlock;
public List<CatchBlock> CatchBlocks;
public List<ILNode> FinallyBlock;
public ILBlock FinallyBlock;
public override IEnumerable<ILNode> GetChildren()
{
yield return this.TryBlock;
foreach (var catchBlock in this.CatchBlocks) {
yield return catchBlock;
}
yield return this.FinallyBlock;
}
public override string ToString()
{
@ -53,7 +114,7 @@ namespace Decompiler @@ -53,7 +114,7 @@ namespace Decompiler
}
public class ILExpression: ILNode
{
{
public OpCode OpCode { get; set; }
public object Operand { get; set; }
public List<ILExpression> Arguments { get; set; }
@ -65,6 +126,22 @@ namespace Decompiler @@ -65,6 +126,22 @@ namespace Decompiler
this.Arguments = new List<ILExpression>(args);
}
public IEnumerable<ILLabel> GetBranchTargets()
{
if (this.Operand is ILLabel) {
return new ILLabel[] { (ILLabel)this.Operand };
} else if (this.Operand is ILLabel[]) {
return (ILLabel[])this.Operand;
} else {
return new ILLabel[] { };
}
}
public override IEnumerable<ILNode> GetChildren()
{
return Arguments;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
@ -84,4 +161,30 @@ namespace Decompiler @@ -84,4 +161,30 @@ namespace Decompiler
return sb.ToString();
}
}
public class ILLoop: ILNode
{
public ILBlock ContentBlock;
public override IEnumerable<ILNode> GetChildren()
{
yield return ContentBlock;
}
}
public class ILCondition: ILNode
{
public ILExpression Condition;
public ILBlock TrueBlock; // Branch was taken
public ILLabel TrueTarget; // Entry label
public ILBlock FalseBlock; // Fall-though
public ILLabel FalseTarget; // Entry label
public override IEnumerable<ILNode> GetChildren()
{
yield return Condition;
yield return TrueBlock;
yield return FalseBlock;
}
}
}

Loading…
Cancel
Save