Browse Source

Add interning support to DefaultAccessor.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
57da5ff3de
  1. 153
      ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs
  2. 4
      ICSharpCode.NRefactory/TypeSystem/DomRegion.cs
  3. 18
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAccessor.cs
  4. 4
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs

153
ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs

@ -17,7 +17,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -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<object>
{
@ -67,98 +67,105 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -67,98 +67,105 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
}
HashSet<object> uniqueObjectsPreIntern = new HashSet<object>(new ReferenceComparer());
HashSet<object> uniqueObjectsPostIntern = new HashSet<object>(new ReferenceComparer());
Dictionary<object, object> byValueDict = new Dictionary<object, object>();
Dictionary<ISupportsInterning, ISupportsInterning> supportsInternDict = new Dictionary<ISupportsInterning, ISupportsInterning>(new InterningComparer());
Dictionary<IEnumerable<object>, IEnumerable<object>> listDict = new Dictionary<IEnumerable<object>, IEnumerable<object>>(new ListComparer());
public T Intern<T>(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<object> uniqueObjectsPreIntern = new HashSet<object>(new ReferenceComparer());
internal HashSet<object> uniqueObjectsPostIntern = new HashSet<object>(new ReferenceComparer());
internal Dictionary<object, object> byValueDict = new Dictionary<object, object>();
internal Dictionary<ISupportsInterning, ISupportsInterning> supportsInternDict = new Dictionary<ISupportsInterning, ISupportsInterning>(new InterningComparer());
internal Dictionary<IEnumerable<object>, IEnumerable<object>> listDict = new Dictionary<IEnumerable<object>, IEnumerable<object>>(new ListComparer());
public T Intern<T>(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<T> InternList<T>(IList<T> 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<T>(list);
IEnumerable<object> output;
if (listDict.TryGetValue(list, out output))
list = (IList<T>)output;
else
byValueDict.Add(obj, obj);
listDict.Add(list, list);
uniqueObjectsPostIntern.Add(list);
return list;
}
uniqueObjectsPostIntern.Add(obj);
return obj;
}
public IList<T> InternList<T>(IList<T> 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<T>(list);
IEnumerable<object> output;
if (listDict.TryGetValue(list, out output))
list = (IList<T>)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);
}
}//*/
}

4
ICSharpCode.NRefactory/TypeSystem/DomRegion.cs

@ -113,7 +113,9 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -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;
}
}

18
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAccessor.cs

@ -10,7 +10,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -10,7 +10,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary>
/// Default implementation of <see cref="IAccessor"/>.
/// </summary>
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 @@ -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);
}
}
}

4
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs

@ -105,13 +105,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -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;
}
}
}

Loading…
Cancel
Save