From 57da5ff3de980d1efb159d3601a6e9c2652ec0cf Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 6 Dec 2010 22:02:18 +0100 Subject: [PATCH] Add interning support to DefaultAccessor. --- .../TypeSystem/TestInterningProvider.cs | 153 +++++++++--------- .../TypeSystem/DomRegion.cs | 4 +- .../Implementation/DefaultAccessor.cs | 18 ++- .../Implementation/DefaultAttribute.cs | 4 +- 4 files changed, 102 insertions(+), 77 deletions(-) diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs index fcf21713d2..098298bb72 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs @@ -17,7 +17,7 @@ namespace ICSharpCode.NRefactory.TypeSystem { //* Not a real unit test [TestFixture] - public class TestInterningProvider : IInterningProvider + public class TestInterningProvider { sealed class ReferenceComparer : IEqualityComparer { @@ -67,98 +67,105 @@ namespace ICSharpCode.NRefactory.TypeSystem } } - HashSet uniqueObjectsPreIntern = new HashSet(new ReferenceComparer()); - HashSet uniqueObjectsPostIntern = new HashSet(new ReferenceComparer()); - Dictionary byValueDict = new Dictionary(); - Dictionary supportsInternDict = new Dictionary(new InterningComparer()); - Dictionary, IEnumerable> listDict = new Dictionary, IEnumerable>(new ListComparer()); - - public T Intern(T obj) where T : class + sealed class InterningProvider : IInterningProvider { - if (obj == null) - return null; - uniqueObjectsPreIntern.Add(obj); - ISupportsInterning s = obj as ISupportsInterning; - if (s != null) { - ISupportsInterning output; - if (supportsInternDict.TryGetValue(s, out output)) { - obj = (T)output; - } else { - s.PrepareForInterning(this); - if (supportsInternDict.TryGetValue(s, out output)) + internal HashSet uniqueObjectsPreIntern = new HashSet(new ReferenceComparer()); + internal HashSet uniqueObjectsPostIntern = new HashSet(new ReferenceComparer()); + internal Dictionary byValueDict = new Dictionary(); + internal Dictionary supportsInternDict = new Dictionary(new InterningComparer()); + internal Dictionary, IEnumerable> listDict = new Dictionary, IEnumerable>(new ListComparer()); + + public T Intern(T obj) where T : class + { + if (obj == null) + return null; + uniqueObjectsPreIntern.Add(obj); + ISupportsInterning s = obj as ISupportsInterning; + if (s != null) { + ISupportsInterning output; + if (supportsInternDict.TryGetValue(s, out output)) { + obj = (T)output; + } else { + s.PrepareForInterning(this); + if (supportsInternDict.TryGetValue(s, out output)) + obj = (T)output; + else + supportsInternDict.Add(s, s); + } + } else if (obj is IType || Type.GetTypeCode(obj.GetType()) >= TypeCode.Boolean) { + object output; + if (byValueDict.TryGetValue(obj, out output)) obj = (T)output; else - supportsInternDict.Add(s, s); + byValueDict.Add(obj, obj); } - } else if (obj is string || obj is IType || obj is bool || obj is int) { - object output; - if (byValueDict.TryGetValue(obj, out output)) - obj = (T)output; + uniqueObjectsPostIntern.Add(obj); + return obj; + } + + public IList InternList(IList list) where T : class + { + if (list == null) + return null; + uniqueObjectsPreIntern.Add(list); + for (int i = 0; i < list.Count; i++) { + T oldItem = list[i]; + T newItem = Intern(oldItem); + if (oldItem != newItem) { + if (list.IsReadOnly) + list = new T[list.Count]; + list[i] = newItem; + } + } + if (!list.IsReadOnly) + list = new ReadOnlyCollection(list); + IEnumerable output; + if (listDict.TryGetValue(list, out output)) + list = (IList)output; else - byValueDict.Add(obj, obj); + listDict.Add(list, list); + uniqueObjectsPostIntern.Add(list); + return list; } - uniqueObjectsPostIntern.Add(obj); - return obj; - } - - public IList InternList(IList list) where T : class - { - if (list == null) - return null; - uniqueObjectsPreIntern.Add(list); - for (int i = 0; i < list.Count; i++) { - T oldItem = list[i]; - T newItem = Intern(oldItem); - if (oldItem != newItem) { - if (list.IsReadOnly) - list = new T[list.Count]; - list[i] = newItem; + + public void InternProject(IProjectContent pc) + { + foreach (var c in TreeTraversal.PreOrder(pc.GetClasses(), c => c.InnerClasses)) { + Intern(c.Namespace); + Intern(c.Name); + foreach (IMember m in c.Members) { + Intern(m); + } } } - if (!list.IsReadOnly) - list = new ReadOnlyCollection(list); - IEnumerable output; - if (listDict.TryGetValue(list, out output)) - list = (IList)output; - else - listDict.Add(list, list); - uniqueObjectsPostIntern.Add(list); - return list; } [Test] public void PrintStatistics() { - foreach (var c in TreeTraversal.PreOrder(CecilLoaderTests.Mscorlib.GetClasses(), c => c.InnerClasses)) { - Intern(c.Namespace); - Intern(c.Name); - foreach (IMember m in c.Members) { - Intern(m); - } - } - + long startMemory = GC.GetTotalMemory(true); + IProjectContent pc = new CecilLoader().LoadAssemblyFile(typeof(object).Assembly.Location); + long memoryWithFullPC = GC.GetTotalMemory(true) - startMemory; + InterningProvider p = new InterningProvider(); + p.InternProject(pc); + PrintStatistics(p); + p = null; + long memoryWithInternedPC = GC.GetTotalMemory(true) - startMemory; + GC.KeepAlive(pc); + Console.WriteLine(memoryWithInternedPC / 1024 + " KB / " + memoryWithFullPC / 1024 + " KB"); + } + + void PrintStatistics(InterningProvider p) + { var stats = - from obj in uniqueObjectsPreIntern + from obj in p.uniqueObjectsPreIntern group 1 by obj.GetType() into g - join g2 in (from obj in uniqueObjectsPostIntern group 1 by obj.GetType()) on g.Key equals g2.Key + join g2 in (from obj in p.uniqueObjectsPostIntern group 1 by obj.GetType()) on g.Key equals g2.Key orderby g.Key.FullName select new { Type = g.Key, PreCount = g.Count(), PostCount = g2.Count() }; foreach (var element in stats) { Console.WriteLine(element.Type + ": " + element.PostCount + "/" + element.PreCount); } - Console.WriteLine(stats.Sum(r => r.PostCount * SizeOf(r.Type)) / 1024 + " KB / " - + stats.Sum(r => r.PreCount * SizeOf(r.Type)) / 1024 + " KB"); - } - - static int SizeOf(Type t) - { - if (t == typeof(string)) - return 16; - long start = GC.GetTotalMemory(true); - object o = FormatterServices.GetUninitializedObject(t); - long stop = GC.GetTotalMemory(true); - GC.KeepAlive(o); - return (int)Math.Max(8, stop - start); } }//*/ } diff --git a/ICSharpCode.NRefactory/TypeSystem/DomRegion.cs b/ICSharpCode.NRefactory/TypeSystem/DomRegion.cs index 2794b00dbc..78b0cbca34 100644 --- a/ICSharpCode.NRefactory/TypeSystem/DomRegion.cs +++ b/ICSharpCode.NRefactory/TypeSystem/DomRegion.cs @@ -113,7 +113,9 @@ namespace ICSharpCode.NRefactory.TypeSystem public override int GetHashCode() { unchecked { - return BeginColumn + 1100009 * BeginLine + 1200007 * BeginColumn + 1300021 * EndColumn; + int hashCode = fileName != null ? fileName.GetHashCode() : 0; + hashCode ^= BeginColumn + 1100009 * BeginLine + 1200007 * BeginColumn + 1300021 * EndColumn; + return hashCode; } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAccessor.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAccessor.cs index cf5cc0d912..9a8580f0a8 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAccessor.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAccessor.cs @@ -10,7 +10,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// /// Default implementation of . /// - public sealed class DefaultAccessor : AbstractFreezable, IAccessor + public sealed class DefaultAccessor : AbstractFreezable, IAccessor, ISupportsInterning { static readonly DefaultAccessor[] defaultAccessors = CreateDefaultAccessors(); @@ -74,5 +74,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return attributes; } } + + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + attributes = provider.InternList(attributes); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + return (attributes != null ? attributes.GetHashCode() : 0) ^ region.GetHashCode() ^ (int)accessibility; + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + DefaultAccessor a = other as DefaultAccessor; + return a != null && (attributes == a.attributes && accessibility == a.accessibility && region == a.region); + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs index b688e37b57..cb085ca18e 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs @@ -105,13 +105,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation int ISupportsInterning.GetHashCodeForInterning() { - return attributeType.GetHashCode() ^ (positionalArguments != null ? positionalArguments.GetHashCode() : 0) ^ (namedArguments != null ? namedArguments.GetHashCode() : 0); + return attributeType.GetHashCode() ^ (positionalArguments != null ? positionalArguments.GetHashCode() : 0) ^ (namedArguments != null ? namedArguments.GetHashCode() : 0) ^ region.GetHashCode(); } bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) { DefaultAttribute a = other as DefaultAttribute; - return a != null && attributeType == a.attributeType && positionalArguments == a.positionalArguments && namedArguments == a.namedArguments; + return a != null && attributeType == a.attributeType && positionalArguments == a.positionalArguments && namedArguments == a.namedArguments && region == a.region; } } }