Browse Source

Fixed SD2-1510: Too slow startup when DesignerViewContent.cs was open

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3768 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
1a0d6c4cdd
  1. 5
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs
  2. 128
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultClass.cs
  3. 7
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionClass.cs

5
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs

@ -174,12 +174,15 @@ namespace ICSharpCode.SharpDevelop.Dom
|| type.BaseType.FullName == "System.MulticastDelegate"; || type.BaseType.FullName == "System.MulticastDelegate";
} }
protected override bool KeepInheritanceTree {
get { return true; }
}
public CecilClass(ICompilationUnit compilationUnit, IClass declaringType, public CecilClass(ICompilationUnit compilationUnit, IClass declaringType,
TypeDefinition td, string fullName) TypeDefinition td, string fullName)
: base(compilationUnit, declaringType) : base(compilationUnit, declaringType)
{ {
this.FullyQualifiedName = fullName; this.FullyQualifiedName = fullName;
this.KeepInheritanceTree = true;
AddAttributes(compilationUnit.ProjectContent, this.Attributes, td.CustomAttributes); AddAttributes(compilationUnit.ProjectContent, this.Attributes, td.CustomAttributes);

128
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultClass.cs

@ -6,8 +6,9 @@
// </file> // </file>
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace ICSharpCode.SharpDevelop.Dom namespace ICSharpCode.SharpDevelop.Dom
{ {
@ -373,59 +374,102 @@ namespace ICSharpCode.SharpDevelop.Dom
return CompareTo((IClass)o); return CompareTo((IClass)o);
} }
volatile List<IClass> inheritanceTreeCache; sealed class InheritanceTreeCache
{
internal IClass[] inheritanceTree;
internal bool isCreating;
}
volatile InheritanceTreeCache inheritanceTreeCache;
public IEnumerable<IClass> ClassInheritanceTree { public IEnumerable<IClass> ClassInheritanceTree {
get { get {
List<IClass> visitedList = inheritanceTreeCache; // Notes:
if (visitedList != null) // the ClassInheritanceTree must work even if the following things happen:
return visitedList; // - cyclic inheritance
visitedList = new List<IClass>(); // - multithreaded calls
Queue<IReturnType> typesToVisit = new Queue<IReturnType>(); // - recursive calls (the SearchType request done by GetUnderlyingClass() uses ClassInheritanceTree)
bool enqueuedLastBaseType = false; // Especially the recursive calls are tricky, this has caused incorrect behavior (SD2-1474)
bool hasErrors = false; // or performance problems (SD2-1510) in the past.
IClass currentClass = this;
IReturnType nextType;
do {
if (currentClass != null) {
if (!visitedList.Contains(currentClass)) {
visitedList.Add(currentClass);
foreach (IReturnType type in currentClass.BaseTypes) {
typesToVisit.Enqueue(type);
}
}
}
if (typesToVisit.Count > 0) {
nextType = typesToVisit.Dequeue();
} else {
nextType = enqueuedLastBaseType ? null : GetBaseTypeByClassType(this);
enqueuedLastBaseType = true;
}
if (nextType != null) {
currentClass = nextType.GetUnderlyingClass();
if (currentClass == null)
hasErrors = true;
}
} while (nextType != null);
// get the inheritanceTreeCache, creating it if required
// (on demand-creation saves memory - lots of classes never need a ClassInheritanceTree)
InheritanceTreeCache inheritanceTreeCache = this.inheritanceTreeCache;
if (inheritanceTreeCache == null) {
// but ensure only one is created, even when ClassInheritanceTree is called by multiple threads
InheritanceTreeCache newCache = new InheritanceTreeCache();
#pragma warning disable 420
// Warning CS0420: 'ICSharpCode.SharpDevelop.Dom.DefaultClass.inheritanceTreeCache': a reference to a volatile field will not be treated as volatile
// We disable this warning because Interlocked.* treats the location as volatile, even though
// normally ref-parameters in C# lose the volatile modifier.
inheritanceTreeCache = Interlocked.CompareExchange(ref this.inheritanceTreeCache, newCache, null) ?? newCache;
#pragma warning restore 420
}
// A SearchType request causes the inheritance tree to be generated, but if it was // now we have the inheritanceTreeCache -> lock on it
// this classes' base type that caused the SearchType request, the GetUnderlyingClass() lock (inheritanceTreeCache) {
// will fail and we will produce an incomplete inheritance tree. if (inheritanceTreeCache.inheritanceTree == null) {
// So we don't cache incomplete inheritance trees for parsed classes (fixes SD2-1474). // inheritance tree does not exist yet
if (!hasErrors || KeepInheritanceTree) { if (inheritanceTreeCache.isCreating) {
inheritanceTreeCache = visitedList; // this is a recursive call -> don't produce inheritance tree
if (!KeepInheritanceTree) return EmptyList<IClass>.Instance;
DomCache.RegisterForClear(delegate { inheritanceTreeCache = null; }); } else {
// now produce the actual inheritance tree
inheritanceTreeCache.isCreating = true;
inheritanceTreeCache.inheritanceTree = CalculateClassInheritanceTree();
inheritanceTreeCache.isCreating = false;
if (!KeepInheritanceTree)
DomCache.RegisterForClear(ClearCachedInheritanceTree);
}
}
return inheritanceTreeCache.inheritanceTree;
} }
return visitedList;
} }
} }
void ClearCachedInheritanceTree()
{
lock (inheritanceTreeCache) {
inheritanceTreeCache.inheritanceTree = null;
}
}
IClass[] CalculateClassInheritanceTree()
{
List<IClass> visitedList = new List<IClass>();
Queue<IReturnType> typesToVisit = new Queue<IReturnType>();
bool enqueuedLastBaseType = false;
IClass currentClass = this;
IReturnType nextType;
do {
if (currentClass != null) {
if (!visitedList.Contains(currentClass)) {
visitedList.Add(currentClass);
foreach (IReturnType type in currentClass.BaseTypes) {
typesToVisit.Enqueue(type);
}
}
}
if (typesToVisit.Count > 0) {
nextType = typesToVisit.Dequeue();
} else {
nextType = enqueuedLastBaseType ? null : GetBaseTypeByClassType(this);
enqueuedLastBaseType = true;
}
if (nextType != null) {
currentClass = nextType.GetUnderlyingClass();
}
} while (nextType != null);
return visitedList.ToArray();
}
/// <summary> /// <summary>
/// Specifies whether to keep the inheritance tree when the DomCache is cleared. /// Specifies whether to keep the inheritance tree when the DomCache is cleared.
/// </summary> /// </summary>
protected bool KeepInheritanceTree = false; protected virtual bool KeepInheritanceTree {
get { return false; }
}
public IReturnType GetBaseType(int index) public IReturnType GetBaseType(int index)
{ {

7
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionClass.cs

@ -105,8 +105,6 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer
FullyQualifiedName = fullName; FullyQualifiedName = fullName;
} }
this.KeepInheritanceTree = true;
try { try {
AddAttributes(compilationUnit.ProjectContent, this.Attributes, CustomAttributeData.GetCustomAttributes(type)); AddAttributes(compilationUnit.ProjectContent, this.Attributes, CustomAttributeData.GetCustomAttributes(type));
} catch (Exception ex) { } catch (Exception ex) {
@ -184,6 +182,9 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer
} }
} }
} }
protected override bool KeepInheritanceTree {
get { return true; }
}
} }
} }

Loading…
Cancel
Save