From 72c22c5049bd72e969ad8b7646bd35a06e3c2e58 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 29 Jul 2022 10:49:24 -0700 Subject: [PATCH] Switch to ImmutableArray for ChecksumWithCOllection --- .../InternalUtilities/EnumerableExtensions.cs | 12 ++++++++ .../Remote/SerializationValidator.cs | 4 +-- .../SerializerService_ChecksumWithChildren.cs | 28 +++++++++---------- .../Workspace/Solution/ChecksumCollection.cs | 10 +++---- .../Solution/ChecksumWithChildren.cs | 7 +++-- .../Solution/ProjectState_Checksum.cs | 13 +++++---- .../Solution/SolutionState_Checksum.cs | 4 +-- .../Workspace/Solution/StateChecksums.cs | 17 +++++------ 8 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs index 869df3804dc9a..3a2d491f1f2e5 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs @@ -311,6 +311,18 @@ public static ImmutableArray SelectAsArray(this IEnum return builder.ToImmutableAndFree(); } + public static ImmutableArray SelectAsArray(this IReadOnlyCollection? source, Func selector) + { + if (source == null) + return ImmutableArray.Empty; + + var builder = ImmutableArray.CreateBuilder(source.Count); + foreach (var item in source) + builder.Add(selector(item)); + + return builder.MoveToImmutable(); + } + /// /// Maps an immutable array through a function that returns ValueTask, returning the new ImmutableArray. /// diff --git a/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs b/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs index 3e6611bf01bfb..aef6bac0cbe4e 100644 --- a/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs +++ b/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs @@ -258,9 +258,9 @@ internal static void ChecksumWithChildrenEqual(ChecksumObjectCollection ch internal static void ChecksumWithChildrenEqual(ChecksumWithChildren checksums1, ChecksumWithChildren checksums2) { Assert.Equal(checksums1.Checksum, checksums2.Checksum); - Assert.Equal(checksums1.Children.Count, checksums2.Children.Count); + Assert.Equal(checksums1.Children.Length, checksums2.Children.Length); - for (var i = 0; i < checksums1.Children.Count; i++) + for (var i = 0; i < checksums1.Children.Length; i++) { var child1 = checksums1.Children[i]; var child2 = checksums2.Children[i]; diff --git a/src/Workspaces/Core/Portable/Serialization/SerializerService_ChecksumWithChildren.cs b/src/Workspaces/Core/Portable/Serialization/SerializerService_ChecksumWithChildren.cs index cc1e589b51af6..ff759f3340de4 100644 --- a/src/Workspaces/Core/Portable/Serialization/SerializerService_ChecksumWithChildren.cs +++ b/src/Workspaces/Core/Portable/Serialization/SerializerService_ChecksumWithChildren.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Immutable; using System.Threading; +using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Serialization @@ -18,7 +19,7 @@ internal partial class SerializerService private const byte ChecksumKind = 0; private const byte ChecksumWithChildrenKind = 1; - private static readonly ImmutableDictionary> s_creatorMap = CreateCreatorMap(); + private static readonly ImmutableDictionary, ChecksumWithChildren>> s_creatorMap = CreateCreatorMap(); public void SerializeChecksumWithChildren(ChecksumWithChildren checksums, ObjectWriter writer, CancellationToken cancellationToken) { @@ -28,7 +29,7 @@ public void SerializeChecksumWithChildren(ChecksumWithChildren checksums, Object writer.WriteInt32((int)kind); checksums.Checksum.WriteTo(writer); - writer.WriteInt32(checksums.Children.Count); + writer.WriteInt32(checksums.Children.Length); foreach (var child in checksums.Children) { switch (child) @@ -55,35 +56,34 @@ private ChecksumWithChildren DeserializeChecksumWithChildren(ObjectReader reader var checksum = Checksum.ReadFrom(reader); var childrenCount = reader.ReadInt32(); - var children = new object[childrenCount]; + var children = ImmutableArray.CreateBuilder(childrenCount); for (var i = 0; i < childrenCount; i++) { var childKind = reader.ReadByte(); if (childKind == ChecksumKind) { - children[i] = Checksum.ReadFrom(reader); - continue; + children.Add(Checksum.ReadFrom(reader)); } - - if (childKind == ChecksumWithChildrenKind) + else if (childKind == ChecksumWithChildrenKind) { - children[i] = DeserializeChecksumWithChildren(reader, cancellationToken); - continue; + children.Add(DeserializeChecksumWithChildren(reader, cancellationToken)); + } + else + { + throw ExceptionUtilities.UnexpectedValue(childKind); } - - throw ExceptionUtilities.UnexpectedValue(childKind); } - var checksums = s_creatorMap[kind](children); + var checksums = s_creatorMap[kind](children.MoveToImmutable()); Contract.ThrowIfFalse(checksums.Checksum == checksum); return checksums; } - private static ImmutableDictionary> CreateCreatorMap() + private static ImmutableDictionary, ChecksumWithChildren>> CreateCreatorMap() { - return ImmutableDictionary>.Empty + return ImmutableDictionary, ChecksumWithChildren>>.Empty .Add(WellKnownSynchronizationKind.SolutionState, children => new SolutionStateChecksums(children)) .Add(WellKnownSynchronizationKind.ProjectState, children => new ProjectStateChecksums(children)) .Add(WellKnownSynchronizationKind.DocumentState, children => new DocumentStateChecksums(children)) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumCollection.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumCollection.cs index 22f56853ff8ca..e68ae66ea7978 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumCollection.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumCollection.cs @@ -19,15 +19,15 @@ namespace Microsoft.CodeAnalysis.Serialization /// internal class ChecksumCollection : ChecksumWithChildren, IReadOnlyCollection { - public ChecksumCollection(Checksum[] checksums) : this((object[])checksums) + public ChecksumCollection(ImmutableArray checksums) : this(checksums.CastArray()) { } - public ChecksumCollection(object[] checksums) : base(checksums) + public ChecksumCollection(ImmutableArray checksums) : base(checksums) { } - public int Count => Children.Count; + public int Count => Children.Length; public Checksum this[int index] => (Checksum)Children[index]; public IEnumerator GetEnumerator() @@ -62,9 +62,9 @@ internal static void Find( Dictionary result, CancellationToken cancellationToken) { - Contract.ThrowIfFalse(values.Count == checksums.Children.Count); + Contract.ThrowIfFalse(values.Count == checksums.Children.Length); - for (var i = 0; i < checksums.Children.Count; i++) + for (var i = 0; i < checksums.Children.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumWithChildren.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumWithChildren.cs index ce79ace943eaa..e459e21006ba6 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumWithChildren.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumWithChildren.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; namespace Microsoft.CodeAnalysis.Serialization @@ -12,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Serialization /// internal abstract class ChecksumWithChildren : IChecksummedObject { - public ChecksumWithChildren(object[] children) + public ChecksumWithChildren(ImmutableArray children) { Checksum = CreateChecksum(children); Children = children; @@ -20,9 +21,9 @@ public ChecksumWithChildren(object[] children) public Checksum Checksum { get; } - public IReadOnlyList Children { get; } + public ImmutableArray Children { get; } - private static Checksum CreateChecksum(object[] children) + private static Checksum CreateChecksum(ImmutableArray children) { // given children must be either Checksum or Checksums (collection of a checksum) return Checksum.Create(children.Select(c => c as Checksum ?? ((ChecksumCollection)c).Checksum)); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs index cc56ae495bf37..0bf133af770c9 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -59,9 +60,9 @@ private async Task ComputeChecksumsAsync(CancellationToke cancellationToken.ThrowIfCancellationRequested(); var parseOptionsChecksum = GetParseOptionsChecksum(serializer); - var projectReferenceChecksums = ChecksumCache.GetOrCreate(ProjectReferences, _ => new ChecksumCollection(ProjectReferences.Select(r => serializer.CreateChecksum(r, cancellationToken)).ToArray())); - var metadataReferenceChecksums = ChecksumCache.GetOrCreate(MetadataReferences, _ => new ChecksumCollection(MetadataReferences.Select(r => serializer.CreateChecksum(r, cancellationToken)).ToArray())); - var analyzerReferenceChecksums = ChecksumCache.GetOrCreate(AnalyzerReferences, _ => new ChecksumCollection(AnalyzerReferences.Select(r => serializer.CreateChecksum(r, cancellationToken)).ToArray())); + var projectReferenceChecksums = ChecksumCache.GetOrCreate(ProjectReferences, _ => new ChecksumCollection(ProjectReferences.SelectAsArray(r => serializer.CreateChecksum(r, cancellationToken)))); + var metadataReferenceChecksums = ChecksumCache.GetOrCreate(MetadataReferences, _ => new ChecksumCollection(MetadataReferences.SelectAsArray(r => serializer.CreateChecksum(r, cancellationToken)))); + var analyzerReferenceChecksums = ChecksumCache.GetOrCreate(AnalyzerReferences, _ => new ChecksumCollection(AnalyzerReferences.SelectAsArray(r => serializer.CreateChecksum(r, cancellationToken)))); var documentChecksums = await Task.WhenAll(documentChecksumsTasks).ConfigureAwait(false); var additionalChecksums = await Task.WhenAll(additionalDocumentChecksumTasks).ConfigureAwait(false); @@ -71,12 +72,12 @@ private async Task ComputeChecksumsAsync(CancellationToke infoChecksum, compilationOptionsChecksum, parseOptionsChecksum, - documentChecksums: new ChecksumCollection(documentChecksums), + documentChecksums: new ChecksumCollection(ImmutableArray.Create(documentChecksums)), projectReferenceChecksums, metadataReferenceChecksums, analyzerReferenceChecksums, - additionalDocumentChecksums: new ChecksumCollection(additionalChecksums), - analyzerConfigDocumentChecksumCollection: new ChecksumCollection(analyzerConfigDocumentChecksums)); + additionalDocumentChecksums: new ChecksumCollection(ImmutableArray.Create(additionalChecksums)), + analyzerConfigDocumentChecksumCollection: new ChecksumCollection(ImmutableArray.Create(analyzerConfigDocumentChecksums))); } } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken, ErrorSeverity.Critical)) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState_Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState_Checksum.cs index d148ae8dd053f..f1f45fe6bd669 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState_Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState_Checksum.cs @@ -155,12 +155,12 @@ private async Task ComputeChecksumsAsync( } var analyzerReferenceChecksums = ChecksumCache.GetOrCreate(AnalyzerReferences, - _ => new ChecksumCollection(AnalyzerReferences.Select(r => serializer.CreateChecksum(r, cancellationToken)).ToArray())); + _ => new ChecksumCollection(AnalyzerReferences.SelectAsArray(r => serializer.CreateChecksum(r, cancellationToken)))); var projectChecksums = await Task.WhenAll(projectChecksumTasks).ConfigureAwait(false); return new SolutionStateChecksums( attributesChecksum, - new ChecksumCollection(projectChecksums.WhereNotNull().ToArray()), + new ChecksumCollection(projectChecksums.WhereNotNull().ToImmutableArray()), analyzerReferenceChecksums, frozenSourceGeneratedDocumentIdentityChecksum, frozenSourceGeneratedDocumentTextChecksum); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs index 514474361e241..ca252601a9595 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -20,11 +21,11 @@ public SolutionStateChecksums( ChecksumCollection analyzerReferenceChecksums, Checksum frozenSourceGeneratedDocumentIdentity, Checksum frozenSourceGeneratedDocumentText) - : this(new object[] { attributesChecksum, projectChecksums, analyzerReferenceChecksums, frozenSourceGeneratedDocumentIdentity, frozenSourceGeneratedDocumentText }) + : this(ImmutableArray.Create(attributesChecksum, projectChecksums, analyzerReferenceChecksums, frozenSourceGeneratedDocumentIdentity, frozenSourceGeneratedDocumentText)) { } - public SolutionStateChecksums(object[] children) : base(children) + public SolutionStateChecksums(ImmutableArray children) : base(children) { } @@ -100,8 +101,8 @@ public ProjectStateChecksums( ChecksumCollection analyzerReferenceChecksums, ChecksumCollection additionalDocumentChecksums, ChecksumCollection analyzerConfigDocumentChecksumCollection) - : this( - (object)infoChecksum, + : this(ImmutableArray.Create( + infoChecksum, compilationOptionsChecksum, parseOptionsChecksum, documentChecksums, @@ -109,11 +110,11 @@ public ProjectStateChecksums( metadataReferenceChecksums, analyzerReferenceChecksums, additionalDocumentChecksums, - analyzerConfigDocumentChecksumCollection) + analyzerConfigDocumentChecksumCollection)) { } - public ProjectStateChecksums(params object[] children) : base(children) + public ProjectStateChecksums(ImmutableArray children) : base(children) { } @@ -209,11 +210,11 @@ public async Task FindAsync( internal class DocumentStateChecksums : ChecksumWithChildren { public DocumentStateChecksums(Checksum infoChecksum, Checksum textChecksum) - : this((object)infoChecksum, textChecksum) + : this(ImmutableArray.Create(infoChecksum, textChecksum)) { } - public DocumentStateChecksums(params object[] children) : base(children) + public DocumentStateChecksums(ImmutableArray children) : base(children) { }