Browse Source

Use lazy initialization for C# resolved type definitions.

This speeds up creating a new compilation for a single resolve operation by a factor of 10 (for NRefactory.sln; potentially more for larger solutions).
newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
d03d17bbe4
  1. 63
      ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs
  2. 19
      ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs

63
ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs

@ -17,9 +17,10 @@ @@ -17,9 +17,10 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils;
@ -94,11 +95,12 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -94,11 +95,12 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
return root;
} else {
root = new NS(this);
Dictionary<string, NS> dict = new Dictionary<string, NS>();
Dictionary<string, NS> dict = new Dictionary<string, NS>(compilation.NameComparer);
dict.Add(string.Empty, root);
foreach (var pair in GetTypes()) {
NS ns = GetOrAddNamespace(dict, pair.Key.Namespace);
ns.types[pair.Key] = pair.Value;
if (ns.types != null)
ns.types[pair.Key] = pair.Value;
}
return LazyInit.GetOrSet(ref this.rootNamespace, root);
}
@ -171,36 +173,46 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -171,36 +173,46 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
return fullAssemblyName.Substring(0, pos);
}
Dictionary<FullNameAndTypeParameterCount, DefaultResolvedTypeDefinition> typeDict;
Dictionary<FullNameAndTypeParameterCount, Lazy<ITypeDefinition>> typeDict;
Dictionary<FullNameAndTypeParameterCount, DefaultResolvedTypeDefinition> GetTypes()
Dictionary<FullNameAndTypeParameterCount, Lazy<ITypeDefinition>> GetTypes()
{
var dict = this.typeDict;
if (dict != null) {
LazyInit.ReadBarrier();
return dict;
} else {
// Always use the ordinal comparer for the main dictionary so that partial classes
// get merged correctly.
// The compilation's comparer will be used for the per-namespace dictionaries.
var comparer = FullNameAndTypeParameterCountComparer.Ordinal;
dict = projectContent.TopLevelTypeDefinitions
.GroupBy(t => new FullNameAndTypeParameterCount(t.Namespace, t.Name, t.TypeParameters.Count), comparer)
.ToDictionary(g => g.Key, g => new DefaultResolvedTypeDefinition(context, g.ToArray()), comparer);
.ToDictionary(g => g.Key, g => CreateResolvedTypeDefinition(g.ToArray()), comparer);
return LazyInit.GetOrSet(ref this.typeDict, dict);
}
}
Lazy<ITypeDefinition> CreateResolvedTypeDefinition(IUnresolvedTypeDefinition[] parts)
{
return new Lazy<ITypeDefinition>(
() => new DefaultResolvedTypeDefinition(context, parts),
LazyThreadSafetyMode.PublicationOnly);
}
public ITypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount)
{
var key = new FullNameAndTypeParameterCount(ns ?? string.Empty, name, typeParameterCount);
DefaultResolvedTypeDefinition def;
Lazy<ITypeDefinition> def;
if (GetTypes().TryGetValue(key, out def))
return def;
return def.Value;
else
return null;
}
public IEnumerable<ITypeDefinition> TopLevelTypeDefinitions {
get {
return GetTypes().Values;
return GetTypes().Values.Select(t => t.Value);
}
}
@ -216,14 +228,18 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -216,14 +228,18 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
readonly string fullName;
readonly string name;
internal readonly List<NS> childNamespaces = new List<NS>();
internal readonly Dictionary<FullNameAndTypeParameterCount, ITypeDefinition> types;
internal readonly Dictionary<FullNameAndTypeParameterCount, Lazy<ITypeDefinition>> types;
public NS(CSharpAssembly assembly)
{
this.assembly = assembly;
this.fullName = string.Empty;
this.name = string.Empty;
this.types = new Dictionary<FullNameAndTypeParameterCount, ITypeDefinition>(new FullNameAndTypeParameterCountComparer(assembly.compilation.NameComparer));
// Our main dictionary for the CSharpAssembly is using an ordinal comparer.
// If the compilation's comparer isn't ordinal, we need to create a new dictionary with the compilation's comparer.
if (assembly.compilation.NameComparer != StringComparer.Ordinal) {
this.types = new Dictionary<FullNameAndTypeParameterCount, Lazy<ITypeDefinition>>(new FullNameAndTypeParameterCountComparer(assembly.compilation.NameComparer));
}
}
public NS(NS parentNamespace, string fullName, string name)
@ -232,7 +248,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -232,7 +248,8 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
this.parentNamespace = parentNamespace;
this.fullName = fullName;
this.name = name;
this.types = new Dictionary<FullNameAndTypeParameterCount, ITypeDefinition>(parentNamespace.types.Comparer);
if (parentNamespace.types != null)
this.types = new Dictionary<FullNameAndTypeParameterCount, Lazy<ITypeDefinition>>(parentNamespace.types.Comparer);
}
string INamespace.ExternAlias {
@ -256,7 +273,16 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -256,7 +273,16 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
}
IEnumerable<ITypeDefinition> INamespace.Types {
get { return types.Values; }
get {
if (types != null)
return types.Values.Select(t => t.Value);
else
return (
from t in assembly.GetTypes()
where t.Key.Namespace == fullName
select t.Value.Value
);
}
}
ICompilation IResolved.Compilation {
@ -275,7 +301,16 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -275,7 +301,16 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
ITypeDefinition INamespace.GetTypeDefinition(string name, int typeParameterCount)
{
return assembly.GetTypeDefinition(this.fullName, name, typeParameterCount);
if (types != null) {
var key = new FullNameAndTypeParameterCount(fullName, name, typeParameterCount);
Lazy<ITypeDefinition> typeDef;
if (types.TryGetValue(key, out typeDef))
return typeDef.Value;
else
return null;
} else {
return assembly.GetTypeDefinition(fullName, name, typeParameterCount);
}
}
}
}

19
ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs

@ -67,6 +67,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -67,6 +67,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
#region GetAllBaseTypeDefinitions
/// <summary>
/// Gets all base type definitions.
/// The output is ordered so that base types occur before derived types.
/// </summary>
/// <remarks>
/// This is equivalent to type.GetAllBaseTypes().Select(t => t.GetDefinition()).Where(d => d != null).Distinct().
@ -76,30 +77,18 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -76,30 +77,18 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (type == null)
throw new ArgumentNullException("type");
HashSet<ITypeDefinition> typeDefinitions = new HashSet<ITypeDefinition>();
Func<ITypeDefinition, IEnumerable<ITypeDefinition>> recursion =
t => t.DirectBaseTypes.Select(b => b.GetDefinition()).Where(d => d != null && typeDefinitions.Add(d));
ITypeDefinition typeDef = type.GetDefinition();
if (typeDef != null) {
typeDefinitions.Add(typeDef);
return TreeTraversal.PreOrder(typeDef, recursion);
} else {
return TreeTraversal.PreOrder(
type.DirectBaseTypes.Select(b => b.GetDefinition()).Where(d => d != null && typeDefinitions.Add(d)),
recursion);
}
return type.GetAllBaseTypes().Select(t => t.GetDefinition()).Where(d => d != null).Distinct();
}
/// <summary>
/// Gets whether this type definition is derived from the base type defintiion.
/// Gets whether this type definition is derived from the base type definition.
/// </summary>
public static bool IsDerivedFrom(this ITypeDefinition type, ITypeDefinition baseType)
{
if (type.Compilation != baseType.Compilation) {
throw new InvalidOperationException("Both arguments to IsDerivedFrom() must be from the same compilation.");
}
return GetAllBaseTypeDefinitions(type).Contains(baseType);
return type.GetAllBaseTypeDefinitions().Contains(baseType);
}
#endregion

Loading…
Cancel
Save