Browse Source

Move decompilation to background thread.

pull/1/head
Daniel Grunwald 15 years ago
parent
commit
158b10d2fb
  1. 6
      ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraph.cs
  2. 10
      ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs
  3. 3
      ILSpy/Decompiler/CSharpLanguage.cs
  4. 10
      ILSpy/Disassembler/ILLanguage.cs
  5. 4
      ILSpy/ILSpyTreeNode.cs
  6. 36
      ILSpy/ITextOutput.cs
  7. 11
      ILSpy/Language.cs
  8. 56
      ILSpy/MainWindow.xaml.cs
  9. 6
      ILSpy/MethodTreeNode.cs

6
ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraph.cs

@ -23,7 +23,7 @@ using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
namespace ICSharpCode.Decompiler.FlowAnalysis namespace ICSharpCode.Decompiler.FlowAnalysis
@ -97,7 +97,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
} }
} }
public void ComputeDominance() public void ComputeDominance(CancellationToken cancellationToken = default(CancellationToken))
{ {
// A Simple, Fast Dominance Algorithm // A Simple, Fast Dominance Algorithm
// Keith D. Cooper, Timothy J. Harvey and Ken Kennedy // Keith D. Cooper, Timothy J. Harvey and Ken Kennedy
@ -108,6 +108,8 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
changed = false; changed = false;
ResetVisited(); ResetVisited();
cancellationToken.ThrowIfCancellationRequested();
// for all nodes b except the entry point // for all nodes b except the entry point
EntryPoint.TraversePreOrder( EntryPoint.TraversePreOrder(
b => b.Successors, b => b.Successors,

10
ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using ICSharpCode.Decompiler.FlowAnalysis; using ICSharpCode.Decompiler.FlowAnalysis;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
@ -30,11 +31,11 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
/// </summary> /// </summary>
public class ControlStructureDetector public class ControlStructureDetector
{ {
public static ControlStructure DetectStructure(ControlFlowGraph g, IEnumerable<ExceptionHandler> exceptionHandlers) public static ControlStructure DetectStructure(ControlFlowGraph g, IEnumerable<ExceptionHandler> exceptionHandlers, CancellationToken cancellationToken)
{ {
ControlStructure root = new ControlStructure(new HashSet<ControlFlowNode>(g.Nodes), g.EntryPoint, ControlStructureType.Root); ControlStructure root = new ControlStructure(new HashSet<ControlFlowNode>(g.Nodes), g.EntryPoint, ControlStructureType.Root);
DetectExceptionHandling(root, g, exceptionHandlers); DetectExceptionHandling(root, g, exceptionHandlers);
DetectLoops(g, root); DetectLoops(g, root, cancellationToken);
g.ResetVisited(); g.ResetVisited();
return root; return root;
} }
@ -111,12 +112,13 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
#endregion #endregion
#region Loop Detection #region Loop Detection
static void DetectLoops(ControlFlowGraph g, ControlStructure current) static void DetectLoops(ControlFlowGraph g, ControlStructure current, CancellationToken cancellationToken)
{ {
g.ResetVisited(); g.ResetVisited();
cancellationToken.ThrowIfCancellationRequested();
FindLoops(current, current.EntryPoint); FindLoops(current, current.EntryPoint);
foreach (ControlStructure loop in current.Children) foreach (ControlStructure loop in current.Children)
DetectLoops(g, loop); DetectLoops(g, loop, cancellationToken);
} }
static void FindLoops(ControlStructure current, ControlFlowNode node) static void FindLoops(ControlStructure current, ControlFlowNode node)

3
ILSpy/Decompiler/CSharpLanguage.cs

@ -18,6 +18,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.FlowAnalysis; using ICSharpCode.Decompiler.FlowAnalysis;
using Mono.Cecil; using Mono.Cecil;
@ -34,7 +35,7 @@ namespace ICSharpCode.ILSpy.Decompiler
get { return "C#"; } get { return "C#"; }
} }
public override void Decompile(MethodDefinition method, ITextOutput output) public override void Decompile(MethodDefinition method, ITextOutput output, CancellationToken cancellationToken)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

10
ILSpy/Disassembler/ILLanguage.cs

@ -19,6 +19,8 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.FlowAnalysis; using ICSharpCode.Decompiler.FlowAnalysis;
using Mono.Cecil; using Mono.Cecil;
@ -36,10 +38,10 @@ namespace ICSharpCode.ILSpy.Disassembler
} }
public override string Name { public override string Name {
get { return detectControlStructure ? "IL (simplified)" : "IL"; } get { return detectControlStructure ? "IL (structured)" : "IL"; }
} }
public override void Decompile(MethodDefinition method, ITextOutput output) public override void Decompile(MethodDefinition method, ITextOutput output, CancellationToken cancellationToken)
{ {
output.WriteCommentLine("// Method begins at RVA 0x{0:x4}", method.RVA); output.WriteCommentLine("// Method begins at RVA 0x{0:x4}", method.RVA);
output.WriteCommentLine("// Code size {0} (0x{0:x})", method.Body.CodeSize); output.WriteCommentLine("// Code size {0} (0x{0:x})", method.Body.CodeSize);
@ -66,9 +68,9 @@ namespace ICSharpCode.ILSpy.Disassembler
if (detectControlStructure) { if (detectControlStructure) {
var cfg = ControlFlowGraphBuilder.Build(method.Body); var cfg = ControlFlowGraphBuilder.Build(method.Body);
cfg.ComputeDominance(); cfg.ComputeDominance(cancellationToken);
cfg.ComputeDominanceFrontier(); cfg.ComputeDominanceFrontier();
var s = ControlStructureDetector.DetectStructure(cfg, method.Body.ExceptionHandlers); var s = ControlStructureDetector.DetectStructure(cfg, method.Body.ExceptionHandlers, cancellationToken);
WriteStructure(output, s); WriteStructure(output, s);
} else { } else {
foreach (var inst in method.Body.Instructions) { foreach (var inst in method.Body.Instructions) {

4
ILSpy/ILSpyTreeNode.cs

@ -20,6 +20,8 @@ using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.Threading;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
@ -52,7 +54,7 @@ namespace ICSharpCode.ILSpy
return FilterResult.Hidden; return FilterResult.Hidden;
} }
public virtual void Decompile(Language language, ITextOutput output) public virtual void Decompile(Language language, ITextOutput output, CancellationToken cancellationToken)
{ {
} }
} }

36
ILSpy/ITextOutput.cs

@ -38,22 +38,11 @@ namespace ICSharpCode.ILSpy
sealed class ReferenceSegment : TextSegment sealed class ReferenceSegment : TextSegment
{ {
public object Reference; public object Reference;
public ILSpyTreeNode TreeNode;
} }
sealed class SmartTextOutput : ITextOutput sealed class DefinitionLookup
{ {
readonly StringBuilder b = new StringBuilder();
int indent;
bool needsIndent;
Dictionary<object, int> definitions = new Dictionary<object, int>(); Dictionary<object, int> definitions = new Dictionary<object, int>();
TextSegmentCollection<ReferenceSegment> references = new TextSegmentCollection<ReferenceSegment>();
public TextSegmentCollection<ReferenceSegment> References {
get { return references; }
}
public ILSpyTreeNode CurrentTreeNode;
public int GetDefinitionPosition(object definition) public int GetDefinitionPosition(object definition)
{ {
@ -64,6 +53,25 @@ namespace ICSharpCode.ILSpy
return -1; return -1;
} }
public void AddDefinition(object definition, int offset)
{
definitions[definition] = offset;
}
}
sealed class SmartTextOutput : ITextOutput
{
readonly StringBuilder b = new StringBuilder();
int indent;
bool needsIndent;
TextSegmentCollection<ReferenceSegment> references = new TextSegmentCollection<ReferenceSegment>();
public readonly DefinitionLookup DefinitionLookup = new DefinitionLookup();
public TextSegmentCollection<ReferenceSegment> References {
get { return references; }
}
public override string ToString() public override string ToString()
{ {
return b.ToString(); return b.ToString();
@ -118,7 +126,7 @@ namespace ICSharpCode.ILSpy
{ {
WriteIndent(); WriteIndent();
b.Append(text); b.Append(text);
definitions[definition] = b.Length; this.DefinitionLookup.AddDefinition(definition, b.Length);
} }
public void WriteReference(string text, object reference) public void WriteReference(string text, object reference)
@ -127,7 +135,7 @@ namespace ICSharpCode.ILSpy
int start = b.Length; int start = b.Length;
b.Append(text); b.Append(text);
int end = b.Length; int end = b.Length;
references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference, TreeNode = CurrentTreeNode }); references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference });
} }
} }
} }

11
ILSpy/Language.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Threading;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
@ -34,23 +35,23 @@ namespace ICSharpCode.ILSpy
get { return ICSharpCode.AvalonEdit.Highlighting.HighlightingManager.Instance.GetDefinition(this.Name); } get { return ICSharpCode.AvalonEdit.Highlighting.HighlightingManager.Instance.GetDefinition(this.Name); }
} }
public virtual void Decompile(MethodDefinition method, ITextOutput output) public virtual void Decompile(MethodDefinition method, ITextOutput output, CancellationToken cancellationToken)
{ {
} }
public virtual void Decompile(PropertyDefinition property, ITextOutput output) public virtual void Decompile(PropertyDefinition property, ITextOutput output, CancellationToken cancellationToken)
{ {
} }
public virtual void Decompile(FieldDefinition field, ITextOutput output) public virtual void Decompile(FieldDefinition field, ITextOutput output, CancellationToken cancellationToken)
{ {
} }
public virtual void Decompile(EventDefinition ev, ITextOutput output) public virtual void Decompile(EventDefinition ev, ITextOutput output, CancellationToken cancellationToken)
{ {
} }
public virtual void Decompile(TypeDefinition type, ITextOutput output) public virtual void Decompile(TypeDefinition type, ITextOutput output, CancellationToken cancellationToken)
{ {
} }

56
ILSpy/MainWindow.xaml.cs

@ -17,15 +17,19 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.FlowAnalysis; using ICSharpCode.Decompiler.FlowAnalysis;
using ICSharpCode.ILSpy.Disassembler;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Microsoft.Win32; using Microsoft.Win32;
using Mono.Cecil; using Mono.Cecil;
@ -210,31 +214,61 @@ namespace ICSharpCode.ILSpy
} }
} }
SmartTextOutput textOutput; DefinitionLookup definitionLookup;
CancellationTokenSource currentCancellationTokenSource;
void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e) void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if (currentCancellationTokenSource != null)
currentCancellationTokenSource.Cancel();
var myCancellationTokenSource = new CancellationTokenSource();
currentCancellationTokenSource = myCancellationTokenSource;
var task = RunDecompiler(ILSpy.Language.Current,
treeView.SelectedItems.OfType<ILSpyTreeNode>().ToArray(),
myCancellationTokenSource.Token);
task.ContinueWith(
delegate {
try { try {
textEditor.SyntaxHighlighting = ILSpy.Language.Current.SyntaxHighlighting; if (currentCancellationTokenSource == myCancellationTokenSource) {
textOutput = new SmartTextOutput(); currentCancellationTokenSource = null;
foreach (var node in treeView.SelectedItems.OfType<ILSpyTreeNode>()) { try {
textOutput.CurrentTreeNode = node; SmartTextOutput textOutput = task.Result;
node.Decompile(ILSpy.Language.Current, textOutput);
}
referenceElementGenerator.References = textOutput.References; referenceElementGenerator.References = textOutput.References;
definitionLookup = textOutput.DefinitionLookup;
textEditor.SyntaxHighlighting = ILSpy.Language.Current.SyntaxHighlighting;
textEditor.Text = textOutput.ToString(); textEditor.Text = textOutput.ToString();
} catch (Exception ex) { } catch (AggregateException ex) {
textEditor.SyntaxHighlighting = null; textEditor.SyntaxHighlighting = null;
referenceElementGenerator.References = null; referenceElementGenerator.References = null;
textEditor.Text = ex.ToString(); definitionLookup = null;
textEditor.Text = string.Join(Environment.NewLine, ex.InnerExceptions.Select(ie => ie.ToString()));
}
}
} finally {
myCancellationTokenSource.Dispose();
}
},
TaskScheduler.FromCurrentSynchronizationContext());
}
static Task<SmartTextOutput> RunDecompiler(ILSpy.Language language, ILSpyTreeNode[] nodes, CancellationToken cancellationToken)
{
return Task.Factory.StartNew(
delegate {
SmartTextOutput textOutput = new SmartTextOutput();
foreach (var node in nodes) {
cancellationToken.ThrowIfCancellationRequested();
node.Decompile(language, textOutput, cancellationToken);
} }
return textOutput;
});
} }
internal void JumpToReference(ReferenceSegment referenceSegment) internal void JumpToReference(ReferenceSegment referenceSegment)
{ {
object reference = referenceSegment.Reference; object reference = referenceSegment.Reference;
if (textOutput != null) { if (definitionLookup != null) {
int pos = textOutput.GetDefinitionPosition(reference); int pos = definitionLookup.GetDefinitionPosition(reference);
if (pos >= 0) { if (pos >= 0) {
textEditor.TextArea.Focus(); textEditor.TextArea.Focus();
textEditor.Select(pos, 0); textEditor.Select(pos, 0);

6
ILSpy/MethodTreeNode.cs

@ -18,6 +18,8 @@
using System; using System;
using System.Text; using System.Text;
using System.Threading;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Mono.Cecil; using Mono.Cecil;
@ -70,9 +72,9 @@ namespace ICSharpCode.ILSpy
} }
} }
public override void Decompile(Language language, ITextOutput output) public override void Decompile(Language language, ITextOutput output, CancellationToken cancellationToken)
{ {
language.Decompile(method, output); language.Decompile(method, output, cancellationToken);
} }
public override FilterResult Filter(FilterSettings settings) public override FilterResult Filter(FilterSettings settings)

Loading…
Cancel
Save