Browse Source

Initial support for switch statements

pull/10/head
David Srbecký 15 years ago
parent
commit
9937d991e8
  1. 32
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 69
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  3. 35
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

32
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
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;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using Decompiler.ControlFlow;
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;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using Decompiler.ControlFlow;
namespace Decompiler
{
@ -167,6 +167,16 @@ namespace Decompiler @@ -167,6 +167,16 @@ namespace Decompiler
FalseStatement = TransformBlock(conditionalNode.FalseBlock)
};
}
} else if (node is ILSwitch) {
ILSwitch ilSwitch = (ILSwitch)node;
SwitchStatement switchStmt = new SwitchStatement() { Expression = (Expression)TransformExpression(ilSwitch.Condition.Arguments[0]) };
for (int i = 0; i < ilSwitch.CaseBlocks.Count; i++) {
switchStmt.AddChild(new SwitchSection() {
CaseLabels = new CaseLabel[] { new CaseLabel() { Expression = new PrimitiveExpression(i) } },
Statements = new Statement[] { TransformBlock(ilSwitch.CaseBlocks[i]) }
}, SwitchStatement.SwitchSectionRole);
}
yield return switchStmt;
} else if (node is ILTryCatchBlock) {
ILTryCatchBlock tryCatchNode = ((ILTryCatchBlock)node);
List<Ast.CatchClause> catchClauses = new List<CatchClause>();

69
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -217,18 +217,69 @@ namespace Decompiler.ControlFlow @@ -217,18 +217,69 @@ namespace Decompiler.ControlFlow
ILMoveableBlock block = node.UserData as ILMoveableBlock;
if (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;
// Switch
if (label != null &&
condBranch != null && condBranch.Operand is ILLabel[] && condBranch.Arguments.Count > 0 &&
statBranch != null && statBranch.Operand is ILLabel && statBranch.Arguments.Count == 0)
{
ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch };
// Replace the two branches with a conditional structure - this preserves the node label
block.Body.Remove(condBranch);
block.Body.Remove(statBranch);
block.Body.Add(ilSwitch);
ControlFlowNode statTarget = null;
labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget);
// Pull in the conditional code
HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>();
if (statTarget != null)
frontiers.UnionWith(statTarget.DominanceFrontier);
foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) {
ControlFlowNode condTarget = null;
labelToCfNode.TryGetValue(condLabel, out condTarget);
if (condTarget != null)
frontiers.UnionWith(condTarget.DominanceFrontier);
}
foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) {
ControlFlowNode condTarget = null;
labelToCfNode.TryGetValue(condLabel, out condTarget);
ILBlock caseBlock = new ILBlock() { EntryPoint = condLabel };
if (condTarget != null && !frontiers.Contains(condTarget)) {
HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget);
nodes.ExceptWith(content);
caseBlock.Body.AddRange(FindConditions(content, condTarget));
}
ilSwitch.CaseBlocks.Add(caseBlock);
}
// The labels will not be used - kill them
condBranch.Operand = null;
result.Add(block);
nodes.Remove(node);
}
// Two-way branch
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 = null;
ControlFlowNode statTarget = null;
labelToCfNode.TryGetValue((ILLabel)condBranch.Operand, out condTarget);
labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget);
ControlFlowNode condTarget = null;
labelToCfNode.TryGetValue((ILLabel)condBranch.Operand, out condTarget);
ILCondition condition = new ILCondition() {
Condition = condBranch,
@ -236,21 +287,17 @@ namespace Decompiler.ControlFlow @@ -236,21 +287,17 @@ namespace Decompiler.ControlFlow
FalseBlock = new ILBlock() { EntryPoint = (ILLabel)statBranch.Operand }
};
// The label will not be used - kill it
condBranch.Operand = null;
// Replace the two branches with a conditional structure
// Replace the two branches with a conditional structure - this preserves the node label
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>();
if (condTarget != null)
frontiers.UnionWith(condTarget.DominanceFrontier);
if (statTarget != null)
frontiers.UnionWith(statTarget.DominanceFrontier);
if (condTarget != null)
frontiers.UnionWith(condTarget.DominanceFrontier);
if (condTarget != null && !frontiers.Contains(condTarget)) {
HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget);
@ -263,6 +310,10 @@ namespace Decompiler.ControlFlow @@ -263,6 +310,10 @@ namespace Decompiler.ControlFlow
condition.FalseBlock.Body.AddRange(FindConditions(content, statTarget));
}
// The label will not be used - kill it
condBranch.Operand = null;
result.Add(block);
nodes.Remove(node);
}
}

35
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Decompiler.ControlFlow;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Cecil = Mono.Cecil;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Decompiler.ControlFlow;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Cecil = Mono.Cecil;
namespace Decompiler
{
@ -48,6 +48,7 @@ namespace Decompiler @@ -48,6 +48,7 @@ namespace Decompiler
public class ILBlock: ILNode
{
// TODO: This should really be a goto, not a label
public ILLabel EntryPoint;
public List<ILNode> Body;
@ -124,8 +125,8 @@ namespace Decompiler @@ -124,8 +125,8 @@ namespace Decompiler
public int From;
public int To; // Exlusive
public override string ToString()
{
public override string ToString()
{
return string.Format("{0}-{1}", From, To);
}
}
@ -226,4 +227,18 @@ namespace Decompiler @@ -226,4 +227,18 @@ namespace Decompiler
yield return FalseBlock;
}
}
public class ILSwitch: ILNode
{
public ILExpression Condition;
public List<ILBlock> CaseBlocks = new List<ILBlock>();
public override IEnumerable<ILNode> GetChildren()
{
yield return Condition;
foreach (ILBlock caseBlock in this.CaseBlocks) {
yield return caseBlock;
}
}
}
}

Loading…
Cancel
Save