From 391a6bc8b744b6deaac9bbee819866041639ac8b Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 26 Aug 2011 11:05:02 +0200 Subject: [PATCH] Cache resolved SimpleTypeOrNamespaceReference/MemberTypeOrNamespaceReference, and intern those references. --- .../CSharp/Parser/TypeSystemConvertVisitor.cs | 49 +++++++++++++++++- .../MemberTypeOrNamespaceReference.cs | 51 +++++++++++++++++-- .../CSharp/Resolver/ResolveVisitor.cs | 2 +- .../SimpleTypeOrNamespaceReference.cs | 49 ++++++++++++++++-- .../ICSharpCode.NRefactory.csproj | 1 + .../Implementation/SimpleInterningProvider.cs | 15 ------ ICSharpCode.NRefactory/Utils/CacheManager.cs | 7 +++ .../Utils/FastSerializer.cs | 17 +------ .../Utils/ReferenceComparer.cs | 39 ++++++++++++++ 9 files changed, 188 insertions(+), 42 deletions(-) create mode 100644 ICSharpCode.NRefactory/Utils/ReferenceComparer.cs diff --git a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs index 00a75b0373..a557a21578 100644 --- a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs @@ -39,6 +39,17 @@ namespace ICSharpCode.NRefactory.CSharp DefaultTypeDefinition currentTypeDefinition; DefaultMethod currentMethod; + IInterningProvider interningProvider = new SimpleInterningProvider(); + + /// + /// Gets/Sets the interning provider to use. + /// The default value is a new instance. + /// + public IInterningProvider InterningProvider { + get { return interningProvider; } + set { interningProvider = value; } + } + /// /// Creates a new TypeSystemConvertVisitor. /// @@ -201,6 +212,9 @@ namespace ICSharpCode.NRefactory.CSharp td.HasExtensionMethods = td.Methods.Any(m => m.IsExtensionMethod); currentTypeDefinition = (DefaultTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition; + if (interningProvider != null) { + td.ApplyInterningProvider(interningProvider); + } return td; } @@ -231,6 +245,9 @@ namespace ICSharpCode.NRefactory.CSharp } currentTypeDefinition = (DefaultTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition; + if (interningProvider != null) { + td.ApplyInterningProvider(interningProvider); + } return td; } @@ -326,6 +343,9 @@ namespace ICSharpCode.NRefactory.CSharp } currentTypeDefinition.Fields.Add(field); + if (interningProvider != null) { + field.ApplyInterningProvider(interningProvider); + } } return isSingleField ? field : null; } @@ -351,6 +371,9 @@ namespace ICSharpCode.NRefactory.CSharp } currentTypeDefinition.Fields.Add(field); + if (interningProvider != null) { + field.ApplyInterningProvider(interningProvider); + } return field; } #endregion @@ -380,6 +403,9 @@ namespace ICSharpCode.NRefactory.CSharp currentTypeDefinition.Methods.Add(m); currentMethod = null; + if (interningProvider != null) { + m.ApplyInterningProvider(interningProvider); + } return m; } @@ -443,6 +469,9 @@ namespace ICSharpCode.NRefactory.CSharp ConvertParameters(m.Parameters, operatorDeclaration.Parameters); currentTypeDefinition.Methods.Add(m); + if (interningProvider != null) { + m.ApplyInterningProvider(interningProvider); + } return m; } #endregion @@ -471,6 +500,9 @@ namespace ICSharpCode.NRefactory.CSharp ApplyModifiers(ctor, modifiers); currentTypeDefinition.Methods.Add(ctor); + if (interningProvider != null) { + ctor.ApplyInterningProvider(interningProvider); + } return ctor; } #endregion @@ -489,6 +521,9 @@ namespace ICSharpCode.NRefactory.CSharp ConvertAttributes(dtor.Attributes, destructorDeclaration.Attributes); currentTypeDefinition.Methods.Add(dtor); + if (interningProvider != null) { + dtor.ApplyInterningProvider(interningProvider); + } return dtor; } #endregion @@ -509,6 +544,9 @@ namespace ICSharpCode.NRefactory.CSharp p.Getter = ConvertAccessor(propertyDeclaration.Getter, p.Accessibility); p.Setter = ConvertAccessor(propertyDeclaration.Setter, p.Accessibility); currentTypeDefinition.Properties.Add(p); + if (interningProvider != null) { + p.ApplyInterningProvider(interningProvider); + } return p; } @@ -529,6 +567,9 @@ namespace ICSharpCode.NRefactory.CSharp p.Setter = ConvertAccessor(indexerDeclaration.Setter, p.Accessibility); ConvertParameters(p.Parameters, indexerDeclaration.Parameters); currentTypeDefinition.Properties.Add(p); + if (interningProvider != null) { + p.ApplyInterningProvider(interningProvider); + } return p; } @@ -582,6 +623,9 @@ namespace ICSharpCode.NRefactory.CSharp } currentTypeDefinition.Events.Add(ev); + if (interningProvider != null) { + ev.ApplyInterningProvider(interningProvider); + } } return isSingleEvent ? ev : null; } @@ -604,6 +648,9 @@ namespace ICSharpCode.NRefactory.CSharp e.RemoveAccessor = ConvertAccessor(eventDeclaration.RemoveAccessor, e.Accessibility); currentTypeDefinition.Events.Add(e); + if (interningProvider != null) { + e.ApplyInterningProvider(interningProvider); + } return e; } #endregion @@ -841,7 +888,7 @@ namespace ICSharpCode.NRefactory.CSharp } internal static IConstantValue ConvertConstantValue(ITypeReference targetType, AstNode expression, - ITypeDefinition parentTypeDefinition, IMethod parentMethodDefinition, UsingScope parentUsingScope) + ITypeDefinition parentTypeDefinition, IMethod parentMethodDefinition, UsingScope parentUsingScope) { ConstantValueBuilder b = new ConstantValueBuilder(parentTypeDefinition, parentMethodDefinition, parentUsingScope, false); ConstantExpression c = expression.AcceptVisitor(b, null); diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs b/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs index 5ad2ea39e1..93b7a777f8 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.CSharp.Resolver { @@ -26,13 +27,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// Reference to a qualified type or namespace name. /// [Serializable] - public sealed class MemberTypeOrNamespaceReference : ITypeOrNamespaceReference + public sealed class MemberTypeOrNamespaceReference : ITypeOrNamespaceReference, ISupportsInterning { - readonly ITypeOrNamespaceReference target; + ITypeOrNamespaceReference target; readonly ITypeDefinition parentTypeDefinition; readonly UsingScope parentUsingScope; - readonly string identifier; - readonly IList typeArguments; + string identifier; + IList typeArguments; public MemberTypeOrNamespaceReference(ITypeOrNamespaceReference target, string identifier, IList typeArguments, ITypeDefinition parentTypeDefinition, UsingScope parentUsingScope) { @@ -58,6 +59,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public ResolveResult DoResolve(ITypeResolveContext context) { + CacheManager cacheManager = context.CacheManager; + if (cacheManager != null) { + object result; + if (cacheManager.Dictionary.TryGetValue(this, out result)) + return (ResolveResult)result; + } + ResolveResult targetRR = target.DoResolve(context); if (targetRR.IsError) return targetRR; @@ -68,7 +76,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver for (int i = 0; i < typeArgs.Length; i++) { typeArgs[i] = typeArguments[i].Resolve(context); } - return r.ResolveMemberType(targetRR, identifier, typeArgs); + ResolveResult rr = r.ResolveMemberType(targetRR, identifier, typeArgs); + if (cacheManager != null) + cacheManager.Dictionary.TryAdd(this, rr); + return rr; } public NamespaceResolveResult ResolveNamespace(ITypeResolveContext context) @@ -91,5 +102,35 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver else return target.ToString() + "." + identifier + "<" + DotNet35Compat.StringJoin(",", typeArguments) + ">"; } + + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + target = provider.Intern(target); + identifier = provider.Intern(identifier); + typeArguments = provider.InternList(typeArguments); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + int hashCode = 0; + unchecked { + hashCode += 1000000007 * target.GetHashCode(); + if (parentTypeDefinition != null) + hashCode += 1000000009 * parentTypeDefinition.GetHashCode(); + if (parentUsingScope != null) + hashCode += 1000000021 * parentUsingScope.GetHashCode(); + hashCode += 1000000033 * identifier.GetHashCode(); + hashCode += 1000000087 * typeArguments.GetHashCode(); + } + return hashCode; + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + MemberTypeOrNamespaceReference o = other as MemberTypeOrNamespaceReference; + return o != null && this.target == o.target && this.parentTypeDefinition == o.parentTypeDefinition + && this.parentUsingScope == o.parentUsingScope && this.identifier == o.identifier + && this.typeArguments == o.typeArguments; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index 43dde55b04..3f82c0115c 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -1478,7 +1478,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver DomRegion MakeRegion(AstNode node) { - return new DomRegion(parsedFile.FileName, node.StartLocation, node.EndLocation); + return new DomRegion(parsedFile != null ? parsedFile.FileName : null, node.StartLocation, node.EndLocation); } sealed class ExplicitlyTypedLambda : LambdaBase diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs b/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs index 631a1fbd5d..62f2ef2810 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.CSharp.Resolver { @@ -26,12 +27,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// Represents a simple C# name. (a single non-qualified identifier with an optional list of type arguments) /// [Serializable] - public sealed class SimpleTypeOrNamespaceReference : ITypeOrNamespaceReference + public sealed class SimpleTypeOrNamespaceReference : ITypeOrNamespaceReference, ISupportsInterning { readonly ITypeDefinition parentTypeDefinition; readonly UsingScope parentUsingScope; - readonly string identifier; - readonly IList typeArguments; + string identifier; + IList typeArguments; readonly SimpleNameLookupMode lookupMode; public SimpleTypeOrNamespaceReference(string identifier, IList typeArguments, ITypeDefinition parentTypeDefinition, UsingScope parentUsingScope, SimpleNameLookupMode lookupMode = SimpleNameLookupMode.Type) @@ -56,6 +57,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public ResolveResult DoResolve(ITypeResolveContext context) { + CacheManager cacheManager = context.CacheManager; + if (cacheManager != null) { + object result; + if (cacheManager.Dictionary.TryGetValue(this, out result)) + return (ResolveResult)result; + } + CSharpResolver r = new CSharpResolver(context); r.CurrentTypeDefinition = parentTypeDefinition; r.UsingScope = parentUsingScope; @@ -63,7 +71,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver for (int i = 0; i < typeArgs.Length; i++) { typeArgs[i] = typeArguments[i].Resolve(context); } - return r.LookupSimpleNameOrTypeName(identifier, typeArgs, lookupMode); + ResolveResult rr = r.LookupSimpleNameOrTypeName(identifier, typeArgs, lookupMode); + if (cacheManager != null) + cacheManager.Dictionary.TryAdd(this, rr); + return rr; } public NamespaceResolveResult ResolveNamespace(ITypeResolveContext context) @@ -86,5 +97,35 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver else return identifier + "<" + DotNet35Compat.StringJoin(",", typeArguments) + ">"; } + + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + identifier = provider.Intern(identifier); + typeArguments = provider.InternList(typeArguments); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + int hashCode = 0; + unchecked { + if (parentTypeDefinition != null) + hashCode += 1000000007 * parentTypeDefinition.GetHashCode(); + if (parentUsingScope != null) + hashCode += 1000000009 * parentUsingScope.GetHashCode(); + + hashCode += 1000000021 * identifier.GetHashCode(); + hashCode += 1000000033 * typeArguments.GetHashCode(); + hashCode += 1000000087 * (int)lookupMode; + } + return hashCode; + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + SimpleTypeOrNamespaceReference o = other as SimpleTypeOrNamespaceReference; + return o != null && this.parentTypeDefinition == o.parentTypeDefinition + && this.parentUsingScope == o.parentUsingScope && this.identifier == o.identifier + && this.typeArguments == o.typeArguments && this.lookupMode == o.lookupMode; + } } } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 79eb50c7d0..065f5a1074 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -349,6 +349,7 @@ + diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs index 828bb1294e..0aca7d06da 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs @@ -39,21 +39,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation Intern(r); } - sealed class ReferenceComparer : IEqualityComparer - { - public readonly static ReferenceComparer Instance = new ReferenceComparer(); - - public new bool Equals(object a, object b) - { - return ReferenceEquals(a, b); - } - - public int GetHashCode(object obj) - { - return RuntimeHelpers.GetHashCode(obj); - } - } - sealed class InterningComparer : IEqualityComparer { public bool Equals(ISupportsInterning x, ISupportsInterning y) diff --git a/ICSharpCode.NRefactory/Utils/CacheManager.cs b/ICSharpCode.NRefactory/Utils/CacheManager.cs index fd325b812c..25442ecc33 100644 --- a/ICSharpCode.NRefactory/Utils/CacheManager.cs +++ b/ICSharpCode.NRefactory/Utils/CacheManager.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Concurrent; using System.Threading; namespace ICSharpCode.NRefactory.Utils @@ -28,6 +29,12 @@ namespace ICSharpCode.NRefactory.Utils /// This class is thread-safe public sealed class CacheManager : IDisposable { + readonly ConcurrentDictionary dict = new ConcurrentDictionary(ReferenceComparer.Instance); + + public ConcurrentDictionary Dictionary { + get { return dict; } + } + /* Lots of code commented out because I don't know if it's useful, clients can usually replicate * the functionality much more easily and only need the Disposed event to ensure cleanup. * diff --git a/ICSharpCode.NRefactory/Utils/FastSerializer.cs b/ICSharpCode.NRefactory/Utils/FastSerializer.cs index 1fd1053f22..d28d07ab40 100644 --- a/ICSharpCode.NRefactory/Utils/FastSerializer.cs +++ b/ICSharpCode.NRefactory/Utils/FastSerializer.cs @@ -20,10 +20,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; using System.Reflection; using System.Reflection.Emit; -using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace ICSharpCode.NRefactory.Utils @@ -49,19 +47,6 @@ namespace ICSharpCode.NRefactory.Utils #endregion #region Serialization - sealed class ReferenceComparer : IEqualityComparer - { - bool IEqualityComparer.Equals(object a, object b) - { - return a == b; - } - - int IEqualityComparer.GetHashCode(object obj) - { - return RuntimeHelpers.GetHashCode(obj); - } - } - sealed class SerializationType { public readonly int ID; @@ -81,7 +66,7 @@ namespace ICSharpCode.NRefactory.Utils sealed class SerializationContext { - readonly Dictionary objectToID = new Dictionary(new ReferenceComparer()); + readonly Dictionary objectToID = new Dictionary(ReferenceComparer.Instance); readonly List instances = new List(); // index: object ID readonly List objectTypes = new List(); // index: object ID SerializationType stringType; diff --git a/ICSharpCode.NRefactory/Utils/ReferenceComparer.cs b/ICSharpCode.NRefactory/Utils/ReferenceComparer.cs new file mode 100644 index 0000000000..079e837bf2 --- /dev/null +++ b/ICSharpCode.NRefactory/Utils/ReferenceComparer.cs @@ -0,0 +1,39 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace ICSharpCode.NRefactory.Utils +{ + sealed class ReferenceComparer : IEqualityComparer + { + public readonly static ReferenceComparer Instance = new ReferenceComparer(); + + public new bool Equals(object a, object b) + { + return ReferenceEquals(a, b); + } + + public int GetHashCode(object obj) + { + return RuntimeHelpers.GetHashCode(obj); + } + } +}