From a4af0a46f268495e5324918b017c7e96049c54b2 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 6 Feb 2011 11:27:39 +0100 Subject: [PATCH] Move assembly loading from constructor to Loaded event. --- .../FlowAnalysis/ControlStructureDetector.cs | 3 ++ ILSpy/AssemblyList.cs | 16 +++++----- ILSpy/ILSpy.csproj | 3 ++ ILSpy/MainWindow.xaml.cs | 29 +++++++++++++------ ILSpy/TextView/DecompilerTextView.cs | 10 +++++++ ILSpy/TreeNodes/ILSpyTreeNode.cs | 7 +++++ 6 files changed, 51 insertions(+), 17 deletions(-) diff --git a/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs b/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs index 23a15ab32..d46d1519b 100644 --- a/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs +++ b/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs @@ -123,6 +123,9 @@ namespace ICSharpCode.Decompiler.FlowAnalysis // This algorithm is applied recursively for any substructures (both detected loops and exception blocks) + // But maybe we should get rid of this complex stuff and instead treat every backward jump as a loop? + // That should still work with the IL produced by compilers, and has the advantage that the detected loop bodies are consecutive IL regions. + static void DetectLoops(ControlFlowGraph g, ControlStructure current, CancellationToken cancellationToken) { g.ResetVisited(); diff --git a/ILSpy/AssemblyList.cs b/ILSpy/AssemblyList.cs index 73e8c9c10..39323e92c 100644 --- a/ILSpy/AssemblyList.cs +++ b/ILSpy/AssemblyList.cs @@ -30,7 +30,7 @@ using Mono.Cecil; namespace ICSharpCode.ILSpy { /// - /// Describes a list of assemblies. + /// A list of assemblies. /// class AssemblyList { @@ -57,6 +57,13 @@ namespace ICSharpCode.ILSpy Assemblies.Select(asm => new XElement("Assembly", asm.FileName)) ); } + + public bool Dirty { get; set; } + public string ListName { get; set; } + + public readonly ObservableCollection Assemblies = new ObservableCollection(); + + ConcurrentDictionary typeDict = new ConcurrentDictionary(); void Assemblies_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { @@ -73,13 +80,6 @@ namespace ICSharpCode.ILSpy ); } - public bool Dirty { get; set; } - public string ListName { get; set; } - - public readonly ObservableCollection Assemblies = new ObservableCollection(); - - ConcurrentDictionary typeDict = new ConcurrentDictionary(); - public void RegisterTypeNode(TypeTreeNode node) { // called on background loading thread, so we need to use a ConcurrentDictionary diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index e9603f4fa..b966307e5 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -202,5 +202,8 @@ + + + \ No newline at end of file diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 74dae1621..b91412822 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -40,6 +40,7 @@ namespace ICSharpCode.ILSpy /// public partial class MainWindow : Window { + ILSpySettings spySettings; SessionSettings sessionSettings; AssemblyListManager assemblyListManager; AssemblyList assemblyList; @@ -47,10 +48,9 @@ namespace ICSharpCode.ILSpy public MainWindow() { - ILSpySettings spySettings = ILSpySettings.Load(); + spySettings = ILSpySettings.Load(); this.sessionSettings = new SessionSettings(spySettings); this.assemblyListManager = new AssemblyListManager(spySettings); - this.assemblyList = assemblyListManager.LoadList(spySettings, sessionSettings.ActiveAssemblyList); this.DataContext = sessionSettings; this.Left = sessionSettings.WindowBounds.Left; @@ -63,11 +63,25 @@ namespace ICSharpCode.ILSpy InitializeComponent(); decompilerTextView.mainWindow = this; + sessionSettings.FilterSettings.PropertyChanged += filterSettings_PropertyChanged; + + #if DEBUG + AddDebugItemsToToolbar(); + #endif + this.Loaded += new RoutedEventHandler(MainWindow_Loaded); + } + + void MainWindow_Loaded(object sender, RoutedEventArgs e) + { + // Load AssemblyList only in Loaded event so that WPF is initialized before we start the CPU-heavy stuff. + // This makes the UI come up a bit faster. + this.assemblyList = assemblyListManager.LoadList(this.spySettings, sessionSettings.ActiveAssemblyList); + this.spySettings = null; + assemblyListTreeNode = new AssemblyListTreeNode(assemblyList); assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone(); - sessionSettings.FilterSettings.PropertyChanged += new PropertyChangedEventHandler(filterSettings_PropertyChanged); - treeView.Root = assemblyListTreeNode; assemblyListTreeNode.Select = SelectNode; + treeView.Root = assemblyListTreeNode; string[] args = Environment.GetCommandLineArgs(); for (int i = 1; i < args.Length; i++) { @@ -77,10 +91,6 @@ namespace ICSharpCode.ILSpy LoadInitialAssemblies(); SelectNode(FindNodeByPath(sessionSettings.ActiveTreeViewPath)); - - #if DEBUG - AddDebugItemsToToolbar(); - #endif } void LoadInitialAssemblies() @@ -109,7 +119,8 @@ namespace ICSharpCode.ILSpy // filterSettings is mutable; but the ILSpyTreeNode filtering assumes that filter settings are immutable. // Thus, the main window will use one mutable instance (for data-binding), and assign a new clone to the ILSpyTreeNodes whenever the main // mutable instance changes. - assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone(); + if (assemblyListTreeNode != null) + assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone(); if (e.PropertyName == "Language") { TreeView_SelectionChanged(null, null); } diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 8fdff7138..5907898b8 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -120,10 +120,20 @@ namespace ICSharpCode.ILSpy.TextView static Task RunDecompiler(ILSpy.Language language, ILSpyTreeNodeBase[] nodes, DecompilationOptions options) { + if (nodes.Length == 0) { + // If there's nothing to be decompiled, don't bother starting up a thread. + // (Improves perf in some cases since we don't have to wait for the thread-pool to accept our task) + TaskCompletionSource tcs = new TaskCompletionSource(); + tcs.SetResult(new SmartTextOutput()); + return tcs.Task; + } + return Task.Factory.StartNew( delegate { SmartTextOutput textOutput = new SmartTextOutput(); + bool first = true; foreach (var node in nodes) { + if (first) first = false; else textOutput.WriteLine(); options.CancellationToken.ThrowIfCancellationRequested(); node.Decompile(language, textOutput, options); } diff --git a/ILSpy/TreeNodes/ILSpyTreeNode.cs b/ILSpy/TreeNodes/ILSpyTreeNode.cs index 4514f44f6..824306c09 100644 --- a/ILSpy/TreeNodes/ILSpyTreeNode.cs +++ b/ILSpy/TreeNodes/ILSpyTreeNode.cs @@ -118,6 +118,13 @@ namespace ICSharpCode.ILSpy.TreeNodes } else { goto default; } + case NotifyCollectionChangedAction.Remove: + if (e.OldItems.Count == 1) { + visibleChildren.Remove((T)e.OldItems[0]); + break; + } else { + goto default; + } default: ResetChildren(); break;