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