From f47dd374e75d2ea1610f908a35d063be07306896 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 30 Jun 2022 12:52:52 -0700 Subject: [PATCH 1/8] Cache the hash in compilation options --- .../Portable/CSharpCompilationOptions.cs | 6 ++- .../CSharpCompilationOptionsTests.cs | 2 +- .../Compilation/CompilationOptions.cs | 15 +++++- .../Core/Portable/InternalUtilities/Hash.cs | 49 +++++++++++++++++++ .../Core/Portable/PublicAPI.Unshipped.txt | 1 + .../Portable/VisualBasicCompilationOptions.vb | 4 +- 6 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpCompilationOptions.cs b/src/Compilers/CSharp/Portable/CSharpCompilationOptions.cs index 8e0ec9d5aa511..bb782869d4769 100644 --- a/src/Compilers/CSharp/Portable/CSharpCompilationOptions.cs +++ b/src/Compilers/CSharp/Portable/CSharpCompilationOptions.cs @@ -18,7 +18,9 @@ namespace Microsoft.CodeAnalysis.CSharp /// whether to emit an executable or a library, whether to optimize /// generated code, and so on. /// +#pragma warning disable CS0659 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode(). public sealed class CSharpCompilationOptions : CompilationOptions, IEquatable +#pragma warning restore CS0659 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode(). { /// /// Allow unsafe regions (i.e. unsafe modifiers on members and unsafe blocks). @@ -748,9 +750,9 @@ public override bool Equals(object? obj) return this.Equals(obj as CSharpCompilationOptions); } - public override int GetHashCode() + protected override int ComputeHashCode() { - return Hash.Combine(base.GetHashCodeHelper(), + return Hash.Combine(GetHashCodeHelper(), Hash.Combine(this.AllowUnsafe, Hash.Combine(Hash.CombineValues(this.Usings, StringComparer.Ordinal), Hash.Combine(TopLevelBinderFlags.GetHashCode(), this.NullableContextOptions.GetHashCode())))); diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/CSharpCompilationOptionsTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/CSharpCompilationOptionsTests.cs index 6402db2ac68d2..13a70fbfb5f7e 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/CSharpCompilationOptionsTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/CSharpCompilationOptionsTests.cs @@ -354,7 +354,7 @@ public void ConstructorValidation() } /// - /// If this test fails, please update the + /// If this test fails, please update the /// and methods to /// make sure they are doing the right thing with your new field and then update the baseline /// here. diff --git a/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs b/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs index 117354e214d75..dcc5aa05c87cf 100644 --- a/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs +++ b/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs @@ -261,6 +261,8 @@ protected set private readonly Lazy> _lazyErrors; + private int _hashCode; + // Expects correct arguments. internal CompilationOptions( OutputKind outputKind, @@ -651,7 +653,18 @@ protected bool EqualsHelper([NotNullWhen(true)] CompilationOptions? other) return equal; } - public abstract override int GetHashCode(); + public sealed override int GetHashCode() + { + if (_hashCode == 0) + { + var hashCode = ComputeHashCode(); + _hashCode = hashCode == 0 ? 1 : hashCode; + } + + return _hashCode; + } + + protected abstract int ComputeHashCode(); protected int GetHashCodeHelper() { diff --git a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs index a1ea12a025329..a62d96fa110d1 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs @@ -68,6 +68,30 @@ internal static int CombineValues(IEnumerable? values, int maxItemsToHash return hashCode; } + internal static int CombineValues(ImmutableDictionary values, int maxItemsToHash = int.MaxValue) + where TKey : notnull + { + if (values == null) + { + return 0; + } + + var hashCode = 0; + var count = 0; + foreach (var value in values) + { + if (count++ >= maxItemsToHash) + { + break; + } + + // Should end up with a constrained virtual call to object.GetHashCode (i.e. avoid boxing where possible). + hashCode = Hash.Combine(value.GetHashCode(), hashCode); + } + + return hashCode; + } + internal static int CombineValues(T[]? values, int maxItemsToHash = int.MaxValue) { if (values == null) @@ -143,6 +167,31 @@ internal static int CombineValues(IEnumerable? values, StringComparer s return hashCode; } + internal static int CombineValues(ImmutableArray values, StringComparer stringComparer, int maxItemsToHash = int.MaxValue) + { + if (values == null) + { + return 0; + } + + var hashCode = 0; + var count = 0; + foreach (var value in values) + { + if (count++ >= maxItemsToHash) + { + break; + } + + if (value != null) + { + hashCode = Hash.Combine(stringComparer.GetHashCode(value), hashCode); + } + } + + return hashCode; + } + /// /// The offset bias value used in the FNV-1a algorithm /// See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index bf7b9db988916..281e168f10de6 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -71,6 +71,7 @@ Microsoft.CodeAnalysis.ISymbol.Accept(Microsoft.CodeAnalysis Microsoft.CodeAnalysis.SymbolVisitor Microsoft.CodeAnalysis.SymbolVisitor.SymbolVisitor() -> void Microsoft.CodeAnalysis.SyntaxValueProvider.ForAttributeWithMetadataName(string! fullyQualifiedMetadataName, System.Func! predicate, System.Func! transform) -> Microsoft.CodeAnalysis.IncrementalValuesProvider +override sealed Microsoft.CodeAnalysis.CompilationOptions.GetHashCode() -> int override sealed Microsoft.CodeAnalysis.Diagnostic.Equals(object? obj) -> bool *REMOVED*static Microsoft.CodeAnalysis.SyntaxNodeExtensions.ReplaceSyntax(this TRoot! root, System.Collections.Generic.IEnumerable! nodes, System.Func! computeReplacementNode, System.Collections.Generic.IEnumerable! tokens, System.Func! computeReplacementToken, System.Collections.Generic.IEnumerable! trivia, System.Func! computeReplacementTrivia) -> TRoot! static Microsoft.CodeAnalysis.Emit.EditAndContinueMethodDebugInformation.Create(System.Collections.Immutable.ImmutableArray compressedSlotMap, System.Collections.Immutable.ImmutableArray compressedLambdaMap, System.Collections.Immutable.ImmutableArray compressedStateMachineStateMap) -> Microsoft.CodeAnalysis.Emit.EditAndContinueMethodDebugInformation diff --git a/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb b/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb index ff4d41831ce7b..5467e3776775e 100644 --- a/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb +++ b/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb @@ -1117,8 +1117,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Creates a hashcode for this instance. ''' ''' A hashcode representing this instance. - Public Overrides Function GetHashCode() As Integer - Return Hash.Combine(MyBase.GetHashCodeHelper(), + Protected Overrides Function ComputeHashCode() As Integer + Return Hash.Combine(GetHashCodeHelper(), Hash.Combine(Hash.CombineValues(Me.GlobalImports), Hash.Combine(If(Me.RootNamespace IsNot Nothing, StringComparer.Ordinal.GetHashCode(Me.RootNamespace), 0), Hash.Combine(Me.OptionStrict, From 14c61365caa2f77bdf03104a4dfaf44a93cc7fbc Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 30 Jun 2022 12:56:35 -0700 Subject: [PATCH 2/8] Remove --- src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 623654949ba86..5ef408b2f5784 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -1,3 +1,4 @@ +*REMOVED*override Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions.GetHashCode() -> int Microsoft.CodeAnalysis.CSharp.Conversion.ConstrainedToType.get -> Microsoft.CodeAnalysis.ITypeSymbol? Microsoft.CodeAnalysis.CSharp.SyntaxKind.InterpolatedMultiLineRawStringStartToken = 9073 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.InterpolatedRawStringEndToken = 9074 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind From bfaf84b40b02f71c85a7cff289ffd6e615a22f43 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Thu, 30 Jun 2022 12:58:20 -0700 Subject: [PATCH 3/8] Update src/Compilers/Core/Portable/InternalUtilities/Hash.cs --- src/Compilers/Core/Portable/InternalUtilities/Hash.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs index a62d96fa110d1..94082c11877da 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs @@ -85,7 +85,6 @@ internal static int CombineValues(ImmutableDictionary Date: Thu, 30 Jun 2022 12:58:44 -0700 Subject: [PATCH 4/8] Update src/Compilers/Core/Portable/InternalUtilities/Hash.cs --- src/Compilers/Core/Portable/InternalUtilities/Hash.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs index 94082c11877da..0c8baa5de2068 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs @@ -72,18 +72,14 @@ internal static int CombineValues(ImmutableDictionary= maxItemsToHash) - { break; - } hashCode = Hash.Combine(value.GetHashCode(), hashCode); } From 4b6bb8012250da4e0a8bbe034a99ee60457cd927 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Thu, 30 Jun 2022 12:59:26 -0700 Subject: [PATCH 5/8] Update src/Compilers/Core/Portable/InternalUtilities/Hash.cs --- src/Compilers/Core/Portable/InternalUtilities/Hash.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs index 0c8baa5de2068..f2d66d5918316 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/Hash.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/Hash.cs @@ -165,23 +165,17 @@ internal static int CombineValues(IEnumerable? values, StringComparer s internal static int CombineValues(ImmutableArray values, StringComparer stringComparer, int maxItemsToHash = int.MaxValue) { if (values == null) - { return 0; - } var hashCode = 0; var count = 0; foreach (var value in values) { if (count++ >= maxItemsToHash) - { break; - } if (value != null) - { hashCode = Hash.Combine(stringComparer.GetHashCode(value), hashCode); - } } return hashCode; From 895a293a34837bed364c91d5ca884eaafe1ad9d7 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 30 Jun 2022 13:26:52 -0700 Subject: [PATCH 6/8] Fix api --- src/Compilers/Core/Portable/PublicAPI.Unshipped.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 281e168f10de6..a98662b113030 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,4 +1,5 @@ *REMOVED*override abstract Microsoft.CodeAnalysis.Diagnostic.Equals(object? obj) -> bool +*REMOVED*override abstract Microsoft.CodeAnalysis.CompilationOptions.GetHashCode() -> int abstract Microsoft.CodeAnalysis.SymbolVisitor.DefaultResult.get -> TResult Microsoft.CodeAnalysis.Compilation.GetTypesByMetadataName(string! fullyQualifiedMetadataName) -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.GeneratorAttributeSyntaxContext From 8831003fd1f91c7a692931e6470afe7ea6d42365 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 30 Jun 2022 14:40:36 -0700 Subject: [PATCH 7/8] REmove --- src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt index 8b137891791fe..9a31aa7a58e6f 100644 --- a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt @@ -1 +1 @@ - +*REMOVED*Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilationOptions.GetHashCode() -> Integer From 4630dda49ee3b068b6295b0da49508a723b411af Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 30 Jun 2022 19:21:07 -0700 Subject: [PATCH 8/8] Fix tests --- .../Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs | 2 +- .../Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs b/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs index 887a382cc2d3d..77b719b1c0abe 100644 --- a/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs +++ b/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs @@ -57,7 +57,7 @@ public void VerifyUpToDate() { verifyCount(11); verifyCount(10); - verifyCount(62); + verifyCount(63); verifyCount(22); static void verifyCount(int expected) diff --git a/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs b/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs index 59a433c74987d..56bbfeda63996 100644 --- a/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs +++ b/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs @@ -62,7 +62,7 @@ public void VerifyUpToDate() { verifyCount(11); verifyCount(10); - verifyCount(62); + verifyCount(63); verifyCount(9); static void verifyCount(int expected)