Browse Source

Add support for short forms to ControlFlowGraphBuilder.

pull/1/head
Daniel Grunwald 15 years ago
parent
commit
d779383cb8
  1. 10
      ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs
  2. 49
      ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs
  3. 5
      ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs
  4. 12
      ILSpy/Disassembler/ILLanguage.cs
  5. 2
      ILSpy/MainWindow.xaml
  6. 14
      ILSpy/MainWindow.xaml.cs
  7. 5
      ILSpy/ReferenceElementGenerator.cs

10
ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs

@ -79,7 +79,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -79,7 +79,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
void CalculateHasIncomingJumps()
{
foreach (Instruction inst in methodBody.Instructions) {
if (inst.OpCode.OperandType == OperandType.InlineBrTarget) {
if (inst.OpCode.OperandType == OperandType.InlineBrTarget || inst.OpCode.OperandType == OperandType.ShortInlineBrTarget) {
hasIncomingJumps[GetInstructionIndex((Instruction)inst.Operand)] = true;
} else if (inst.OpCode.OperandType == OperandType.InlineSwitch) {
foreach (Instruction i in (Instruction[])inst.Operand)
@ -138,8 +138,8 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -138,8 +138,8 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
CreateEdge(node, node.End.Next, JumpType.Normal);
// create edges for branch instructions
if (node.End.OpCode.OperandType == OperandType.InlineBrTarget) {
if (node.End.OpCode == OpCodes.Leave) {
if (node.End.OpCode.OperandType == OperandType.InlineBrTarget || node.End.OpCode.OperandType == OperandType.ShortInlineBrTarget) {
if (node.End.OpCode == OpCodes.Leave || node.End.OpCode == OpCodes.Leave_S) {
var handlerBlock = FindInnermostHandlerBlock(node.End.Offset);
if (handlerBlock.NodeType == ControlFlowNodeType.FinallyOrFaultHandler)
CreateEdge(node, (Instruction)node.End.Operand, JumpType.LeaveTry);
@ -245,7 +245,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -245,7 +245,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
for (int i = nodes.Count - 1; i >= 0; i--) {
ControlFlowNode node = nodes[i];
if (node.End != null && node.Outgoing.Count == 1 && node.Outgoing[0].Type == JumpType.LeaveTry) {
Debug.Assert(node.End.OpCode == OpCodes.Leave);
Debug.Assert(node.End.OpCode == OpCodes.Leave || node.End.OpCode == OpCodes.Leave_S);
ControlFlowNode target = node.Outgoing[0].Target;
// remove the edge
@ -267,7 +267,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -267,7 +267,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
for (int i = nodes.Count - 1; i >= 0; i--) {
ControlFlowNode node = nodes[i];
if (node.End != null && node.Outgoing.Count == 1 && node.Outgoing[0].Type == JumpType.LeaveTry) {
Debug.Assert(node.End.OpCode == OpCodes.Leave);
Debug.Assert(node.End.OpCode == OpCodes.Leave || node.End.OpCode == OpCodes.Leave_S);
ControlFlowNode target = node.Outgoing[0].Target;
// remove the edge

49
ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs

@ -37,19 +37,32 @@ namespace ICSharpCode.Decompiler @@ -37,19 +37,32 @@ namespace ICSharpCode.Decompiler
new OpCodeInfo(OpCodes.And) { CanThrow = false },
new OpCodeInfo(OpCodes.Arglist) { CanThrow = false },
new OpCodeInfo(OpCodes.Beq) { CanThrow = false },
new OpCodeInfo(OpCodes.Beq_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Bge) { CanThrow = false },
new OpCodeInfo(OpCodes.Bge_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Bge_Un) { CanThrow = false },
new OpCodeInfo(OpCodes.Bge_Un_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Bgt) { CanThrow = false },
new OpCodeInfo(OpCodes.Bgt_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Bgt_Un) { CanThrow = false },
new OpCodeInfo(OpCodes.Bgt_Un_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Ble) { CanThrow = false },
new OpCodeInfo(OpCodes.Ble_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Ble_Un) { CanThrow = false },
new OpCodeInfo(OpCodes.Ble_Un_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Blt) { CanThrow = false },
new OpCodeInfo(OpCodes.Blt_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Blt_Un) { CanThrow = false },
new OpCodeInfo(OpCodes.Blt_Un_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Bne_Un) { CanThrow = false },
new OpCodeInfo(OpCodes.Bne_Un_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Br) { CanThrow = false },
new OpCodeInfo(OpCodes.Br_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Break) { CanThrow = true },
new OpCodeInfo(OpCodes.Brfalse) { CanThrow = false },
new OpCodeInfo(OpCodes.Brfalse_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Brtrue) { CanThrow = false },
new OpCodeInfo(OpCodes.Brtrue_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Call) { CanThrow = true },
new OpCodeInfo(OpCodes.Calli) { CanThrow = true },
new OpCodeInfo(OpCodes.Ceq) { CanThrow = false },
@ -103,9 +116,26 @@ namespace ICSharpCode.Decompiler @@ -103,9 +116,26 @@ namespace ICSharpCode.Decompiler
new OpCodeInfo(OpCodes.Endfinally) { CanThrow = false },
//new OpCodeInfo(OpCodes.Initblk) { CanThrow = true }, - no idea whether this might cause trouble for the type system, C# shouldn't use it so I'll disable it
//new OpCodeInfo(OpCodes.Jmp) { CanThrow = true } - We don't support non-local control transfers.
new OpCodeInfo(OpCodes.Ldarg) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldarga) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldarg) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldarg_0) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldarg_1) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldarg_2) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldarg_3) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldarg_S) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldarga) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldarga_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_M1) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_0) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_1) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_2) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_3) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_4) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_5) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_6) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_7) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_8) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I4_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_I8) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_R4) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldc_R8) { CanThrow = false },
@ -124,9 +154,16 @@ namespace ICSharpCode.Decompiler @@ -124,9 +154,16 @@ namespace ICSharpCode.Decompiler
new OpCodeInfo(OpCodes.Ldind_Ref) { CanThrow = true },
// the ldloc exceptions described in the spec can only occur on methods without .localsinit - but csc always sets that flag
new OpCodeInfo(OpCodes.Ldloc) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldloc_0) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldloc_1) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldloc_2) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldloc_3) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldloc_S) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Ldloca) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldloca_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Ldnull) { CanThrow = false },
new OpCodeInfo(OpCodes.Leave) { CanThrow = false },
new OpCodeInfo(OpCodes.Leave_S) { CanThrow = false },
new OpCodeInfo(OpCodes.Localloc) { CanThrow = true },
new OpCodeInfo(OpCodes.Mul) { CanThrow = false },
new OpCodeInfo(OpCodes.Mul_Ovf) { CanThrow = true },
@ -143,6 +180,7 @@ namespace ICSharpCode.Decompiler @@ -143,6 +180,7 @@ namespace ICSharpCode.Decompiler
new OpCodeInfo(OpCodes.Shr) { CanThrow = false },
new OpCodeInfo(OpCodes.Shr_Un) { CanThrow = false },
new OpCodeInfo(OpCodes.Starg) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Starg_S) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Stind_I1) { CanThrow = true },
new OpCodeInfo(OpCodes.Stind_I2) { CanThrow = true },
new OpCodeInfo(OpCodes.Stind_I4) { CanThrow = true },
@ -152,6 +190,11 @@ namespace ICSharpCode.Decompiler @@ -152,6 +190,11 @@ namespace ICSharpCode.Decompiler
new OpCodeInfo(OpCodes.Stind_I) { CanThrow = true },
new OpCodeInfo(OpCodes.Stind_Ref) { CanThrow = true },
new OpCodeInfo(OpCodes.Stloc) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Stloc_0) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Stloc_1) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Stloc_2) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Stloc_3) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Stloc_S) { CanThrow = false, IsMoveInstruction = true },
new OpCodeInfo(OpCodes.Sub) { CanThrow = false },
new OpCodeInfo(OpCodes.Sub_Ovf) { CanThrow = true },
new OpCodeInfo(OpCodes.Sub_Ovf_Un) { CanThrow = true },

5
ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs

@ -159,6 +159,11 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -159,6 +159,11 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
case JumpType.Normal:
newStackSize = stackSize;
break;
case JumpType.EndFinally:
if (stackSize != 0)
throw new NotSupportedException("stacksize must be 0 in endfinally edge");
newStackSize = 0;
break;
case JumpType.MutualProtection:
case JumpType.JumpToExceptionHandler:
switch (edge.Target.NodeType) {

12
ILSpy/Disassembler/ILLanguage.cs

@ -28,11 +28,16 @@ namespace ICSharpCode.ILSpy.Disassembler @@ -28,11 +28,16 @@ namespace ICSharpCode.ILSpy.Disassembler
{
public class ILLanguage : Language
{
public override string Name {
get { return "IL"; }
bool detectControlStructure;
public ILLanguage(bool detectControlStructure)
{
this.detectControlStructure = detectControlStructure;
}
bool detectControlStructure = true;
public override string Name {
get { return detectControlStructure ? "IL (simplified)" : "IL"; }
}
public override void Decompile(MethodDefinition method, ITextOutput output)
{
@ -60,7 +65,6 @@ namespace ICSharpCode.ILSpy.Disassembler @@ -60,7 +65,6 @@ namespace ICSharpCode.ILSpy.Disassembler
output.WriteLine();
if (detectControlStructure) {
method.Body.SimplifyMacros();
var cfg = ControlFlowGraphBuilder.Build(method.Body);
cfg.ComputeDominance();
cfg.ComputeDominanceFrontier();

2
ILSpy/MainWindow.xaml

@ -64,7 +64,7 @@ @@ -64,7 +64,7 @@
<Image Width="16" Height="16" Source="Images/PrivateInternal.png" />
</CheckBox>
<Separator />
<ComboBox Name="languageComboBox" DisplayMemberPath="Name" Width="50" SelectionChanged="LanguageComboBox_SelectionChanged" />
<ComboBox Name="languageComboBox" DisplayMemberPath="Name" Width="100" SelectionChanged="LanguageComboBox_SelectionChanged" />
</ToolBar>
<!-- Main grid separating left pane (treeView) from main pane (textEditor) -->
<Grid>

14
ILSpy/MainWindow.xaml.cs

@ -20,17 +20,16 @@ using System; @@ -20,17 +20,16 @@ using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.FlowAnalysis;
using ICSharpCode.TreeView;
using Microsoft.Win32;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
namespace ICSharpCode.ILSpy
@ -44,7 +43,7 @@ namespace ICSharpCode.ILSpy @@ -44,7 +43,7 @@ namespace ICSharpCode.ILSpy
FilterSettings filterSettings = new FilterSettings();
ReferenceElementGenerator referenceElementGenerator;
static readonly Assembly[] initialAssemblies = {
static readonly System.Reflection.Assembly[] initialAssemblies = {
typeof(object).Assembly,
typeof(Uri).Assembly,
typeof(System.Linq.Enumerable).Assembly,
@ -61,16 +60,17 @@ namespace ICSharpCode.ILSpy @@ -61,16 +60,17 @@ namespace ICSharpCode.ILSpy
public MainWindow()
{
referenceElementGenerator = new ReferenceElementGenerator(this);
this.DataContext = filterSettings;
InitializeComponent();
languageComboBox.Items.Add(new Decompiler.CSharpLanguage());
languageComboBox.Items.Add(new Disassembler.ILLanguage());
languageComboBox.Items.Add(new Disassembler.ILLanguage(false));
languageComboBox.Items.Add(new Disassembler.ILLanguage(true));
languageComboBox.SelectedItem = languageComboBox.Items[0];
textEditor.Text = "Welcome to ILSpy!";
referenceElementGenerator = new ReferenceElementGenerator(this);
textEditor.TextArea.TextView.ElementGenerators.Add(referenceElementGenerator);
AssemblyListTreeNode assemblyListTreeNode = new AssemblyListTreeNode(assemblyList);
@ -84,7 +84,7 @@ namespace ICSharpCode.ILSpy @@ -84,7 +84,7 @@ namespace ICSharpCode.ILSpy
treeView.Root = assemblyListTreeNode;
assemblyListTreeNode.Select = SelectNode;
foreach (Assembly asm in initialAssemblies)
foreach (System.Reflection.Assembly asm in initialAssemblies)
assemblyList.OpenAssembly(asm.Location);
string[] args = Environment.GetCommandLineArgs();
for (int i = 1; i < args.Length; i++) {
@ -125,7 +125,6 @@ namespace ICSharpCode.ILSpy @@ -125,7 +125,6 @@ namespace ICSharpCode.ILSpy
{
MethodTreeNode node = treeView.SelectedItem as MethodTreeNode;
if (node != null && node.MethodDefinition.HasBody) {
node.MethodDefinition.Body.SimplifyMacros();
var cfg = ControlFlowGraphBuilder.Build(node.MethodDefinition.Body);
cfg.ComputeDominance();
cfg.ComputeDominanceFrontier();
@ -226,6 +225,7 @@ namespace ICSharpCode.ILSpy @@ -226,6 +225,7 @@ namespace ICSharpCode.ILSpy
textEditor.Text = textOutput.ToString();
} catch (Exception ex) {
textEditor.SyntaxHighlighting = null;
referenceElementGenerator.References = null;
textEditor.Text = ex.ToString();
}
}

5
ILSpy/ReferenceElementGenerator.cs

@ -33,8 +33,9 @@ namespace ICSharpCode.ILSpy @@ -33,8 +33,9 @@ namespace ICSharpCode.ILSpy
if (this.References == null)
return null;
foreach (var segment in this.References.FindSegmentsContaining(offset)) {
if (offset < segment.EndOffset) {
return new VisualLineReferenceText(CurrentContext.VisualLine, segment.EndOffset - offset, this, segment);
int endOffset = Math.Min(segment.EndOffset, CurrentContext.VisualLine.LastDocumentLine.EndOffset);
if (offset < endOffset) {
return new VisualLineReferenceText(CurrentContext.VisualLine, endOffset - offset, this, segment);
}
}
return null;

Loading…
Cancel
Save