From 051ac82ebb5ab9ecb9a4ca9257328cba18277ba9 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:03:43 -0700 Subject: [PATCH 01/24] Spelling --- src/Workspaces/Remote/Core/AbstractAssetProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs index 50b8520138855..33b88c0d515d4 100644 --- a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs +++ b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs @@ -34,7 +34,7 @@ public async Task CreateSolutionInfoAsync(Checksum solutionChecksu var solutionAttributes = await GetAssetAsync(AssetPathKind.SolutionAttributes, solutionChecksums.Attributes, cancellationToken).ConfigureAwait(false); await GetAssetAsync(AssetPathKind.SolutionSourceGeneratorExecutionVersionMap, solutionCompilationChecksums.SourceGeneratorExecutionVersionMap, cancellationToken).ConfigureAwait(false); - // Fetch all the project state checksums up front. That allows gettign all the data in a single call, and + // Fetch all the project state checksums up front. That allows getting all the data in a single call, and // enables parallel fetching of the projects below. using var _1 = ArrayBuilder.GetInstance(solutionChecksums.Projects.Length, out var allProjectStateChecksums); await this.GetAssetsAsync>( From 17c6ce773f62ad328e39314f0b0228e1ef244486 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:08:48 -0700 Subject: [PATCH 02/24] Simplify --- .../Remote/Core/AbstractAssetProvider.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs index 33b88c0d515d4..2bc5d7ac459ef 100644 --- a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs +++ b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs @@ -36,19 +36,15 @@ public async Task CreateSolutionInfoAsync(Checksum solutionChecksu // Fetch all the project state checksums up front. That allows getting all the data in a single call, and // enables parallel fetching of the projects below. - using var _1 = ArrayBuilder.GetInstance(solutionChecksums.Projects.Length, out var allProjectStateChecksums); - await this.GetAssetsAsync>( + using var _1 = ArrayBuilder>.GetInstance(solutionChecksums.Projects.Length, out var projectsTasks); + await this.GetAssetHelper().GetAssetsAsync( AssetPathKind.ProjectStateChecksums, solutionChecksums.Projects.Checksums, - static (_, projectStateChecksums, allProjectStateChecksums) => allProjectStateChecksums.Add(projectStateChecksums), - allProjectStateChecksums, + static (_, projectStateChecksums, tuple) => tuple.projectsTasks.Add(tuple.@this.CreateProjectInfoAsync(projectStateChecksums, tuple.cancellationToken)), + (@this: this, projectsTasks, cancellationToken), cancellationToken).ConfigureAwait(false); // Fetch the projects in parallel. - using var _2 = ArrayBuilder>.GetInstance(solutionChecksums.Projects.Length, out var projectsTasks); - foreach (var projectStateChecksum in allProjectStateChecksums) - projectsTasks.Add(CreateProjectInfoAsync(projectStateChecksum, cancellationToken)); - var analyzerReferences = await this.GetAssetsArrayAsync(AssetPathKind.SolutionAnalyzerReferences, solutionChecksums.AnalyzerReferences, cancellationToken).ConfigureAwait(false); var projects = await Task.WhenAll(projectsTasks).ConfigureAwait(false); @@ -152,6 +148,18 @@ public async Task CreateDocumentInfoAsync( // TODO: do we need version? return new DocumentInfo(attributes, textLoader, documentServiceProvider: null); } + + public AssetHelper GetAssetHelper() + => new(this); + + public readonly struct AssetHelper(AbstractAssetProvider assetProvider) + { + public Task GetAssetsAsync(AssetPath assetPath, HashSet checksums, Action? callback, TArg? arg, CancellationToken cancellationToken) + => assetProvider.GetAssetsAsync(assetPath, checksums, callback, arg, cancellationToken); + + public Task GetAssetsAsync(AssetPath assetPath, ChecksumCollection checksums, Action? callback, TArg? arg, CancellationToken cancellationToken) + => assetProvider.GetAssetsAsync(assetPath, checksums, callback, arg, cancellationToken); + } } internal static class AbstractAssetProviderExtensions From 8742f426868c612f095aaea001efb281db2ae790 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:09:54 -0700 Subject: [PATCH 03/24] Simplify types --- src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs b/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs index 06c57485f348a..4d484533e1850 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs @@ -43,7 +43,7 @@ public override async ValueTask GetAssetAsync( checksums.Add(checksum); using var _2 = ArrayBuilder.GetInstance(1, out var builder); - await this.GetAssetsAsync>( + await this.GetAssetHelper().GetAssetsAsync( assetPath, checksums, static (_, asset, builder) => builder.Add(asset), builder, cancellationToken).ConfigureAwait(false); From 99819ba019f46fc93769332f78d3d55bf9bc82d1 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:10:48 -0700 Subject: [PATCH 04/24] Simplify types --- .../Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs | 2 +- .../Services/SourceGeneration/RemoteSourceGenerationService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs index d65562f56b02c..ae6756e6fefaa 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs @@ -223,7 +223,7 @@ private async Task UpdateProjectsAsync( using var _5 = PooledHashSet.GetInstance(out var newChecksumsToSync); newChecksumsToSync.AddRange(newProjectIdToChecksum.Values); - await _assetProvider.GetAssetsAsync>( + await _assetProvider.GetAssetHelper().GetAssetsAsync( assetPath: AssetPathKind.ProjectStateChecksums, newChecksumsToSync, static (checksum, newProjectStateChecksum, newProjectIdToStateChecksums) => { diff --git a/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs b/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs index 5a5a17d0021a4..6a974e5c64b6c 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs @@ -115,7 +115,7 @@ public async ValueTask HasGeneratorsAsync( // the host will cache it. We'll only actually fetch something new and compute something new when an actual new // analyzer reference is added. using var _2 = ArrayBuilder.GetInstance(checksums.Count, out var analyzerReferences); - await assetProvider.GetAssetsAsync>( + await assetProvider.GetAssetHelper().GetAssetsAsync( projectId, checksums, static (_, analyzerReference, analyzerReferences) => analyzerReferences.Add(analyzerReference), From 45026384d6c71e4ca6d8bfb406d4630f6ee0d8b0 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:18:02 -0700 Subject: [PATCH 05/24] Remove garbage --- .../InternalUtilities/EnumerableExtensions.cs | 12 ++++++++++++ .../Solution/SolutionCompilationState_Checksum.cs | 7 ++++++- .../Portable/Workspace/Solution/StateChecksums.cs | 8 +++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs index b299b637fc11a..5eaacc8f204c0 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs @@ -19,6 +19,18 @@ namespace Roslyn.Utilities { internal static partial class EnumerableExtensions { + public static int Count(this IEnumerable source, Func predicate, TArg arg) + { + var count = 0; + foreach (var v in source) + { + if (predicate(v, arg)) + count++; + } + + return count; + } + public static IEnumerable Do(this IEnumerable source, Action action) { if (source == null) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs index af37ec21138f8..134642f20beed 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; @@ -163,8 +164,12 @@ static Checksum GetVersionMapChecksum(SolutionCompilationState @this) // We want the projects in sorted order so we can generate the checksum for the // source-generation-execution-map consistently. var sortedProjectIds = SolutionState.GetOrCreateSortedProjectIds(@this.SolutionState.ProjectIds); + var supportedCount = sortedProjectIds.Count( + static (projectId, @this) => RemoteSupportedLanguages.IsSupported(@this.SolutionState.GetRequiredProjectState(projectId).Language), + @this); - using var _ = ArrayBuilder.GetInstance(out var checksums); + // For each project, we'll add one checksum for the project id and one for the version map. + using var _ = ArrayBuilder.GetInstance(2 * supportedCount, out var checksums); foreach (var projectId in sortedProjectIds) { diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs index 161d55e65cc93..372b4d34a8072 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.Resources; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; @@ -534,11 +535,12 @@ public static ChecksumCollection GetOrCreateChecksumCollection( references, static (references, tuple) => { - using var _ = ArrayBuilder.GetInstance(references.Count, out var checksums); + var checksums = new Checksum[references.Count]; + var index = 0; foreach (var reference in references) - checksums.Add(tuple.serializer.CreateChecksum(reference, tuple.cancellationToken)); + checksums[index++] = tuple.serializer.CreateChecksum(reference, tuple.cancellationToken); - return new ChecksumCollection(checksums.ToImmutableAndClear()); + return new ChecksumCollection(ImmutableCollectionsMarshal.AsImmutableArray(checksums)); }, (serializer, cancellationToken)); } From 85456591da15d202e8930b1ce577e497eeb136ea Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:19:06 -0700 Subject: [PATCH 06/24] Remove garbage --- .../Workspace/Solution/TextDocumentStates.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs index 713a76b23060b..be4f6772f7905 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -321,19 +322,21 @@ static async (state, _, cancellationToken) => public async ValueTask GetDocumentChecksumsAndIdsAsync(CancellationToken cancellationToken) { - using var _1 = ArrayBuilder.GetInstance(_map.Count, out var attributeChecksums); - using var _2 = ArrayBuilder.GetInstance(_map.Count, out var textChecksums); + var attributeChecksums = new Checksum[_map.Count]; + var textChecksums = new Checksum[_map.Count]; + var index = 0; foreach (var (_, state) in _map) { var stateChecksums = await state.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - attributeChecksums.Add(stateChecksums.Info); - textChecksums.Add(stateChecksums.Text); + attributeChecksums[index] = stateChecksums.Info; + textChecksums[index] = stateChecksums.Text; + index++; } return new( - new ChecksumCollection(attributeChecksums.ToImmutableAndClear()), - new ChecksumCollection(textChecksums.ToImmutableAndClear()), + new ChecksumCollection(ImmutableCollectionsMarshal.AsImmutableArray(attributeChecksums)), + new ChecksumCollection(ImmutableCollectionsMarshal.AsImmutableArray(textChecksums)), SelectAsArray(static s => s.Id)); } From 7850f214ea6737e81ed70c2c5415c722ff0344c6 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:19:23 -0700 Subject: [PATCH 07/24] Docs --- src/Workspaces/Remote/Core/AbstractAssetProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs index 2bc5d7ac459ef..9d8a029f2ebc1 100644 --- a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs +++ b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs @@ -44,9 +44,9 @@ await this.GetAssetHelper().GetAssetsAsync( (@this: this, projectsTasks, cancellationToken), cancellationToken).ConfigureAwait(false); - // Fetch the projects in parallel. var analyzerReferences = await this.GetAssetsArrayAsync(AssetPathKind.SolutionAnalyzerReferences, solutionChecksums.AnalyzerReferences, cancellationToken).ConfigureAwait(false); + // Fetch the projects in parallel. var projects = await Task.WhenAll(projectsTasks).ConfigureAwait(false); return SolutionInfo.Create( solutionAttributes.Id, From ed7a495709057f92766be600a07364ca0b72a40c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:20:38 -0700 Subject: [PATCH 08/24] Cleanup --- src/Workspaces/Remote/Core/AbstractAssetProvider.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs index 9d8a029f2ebc1..22fdc549072c8 100644 --- a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs +++ b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs @@ -95,15 +95,16 @@ public async Task CreateProjectInfoAsync(ProjectStateChecksums proj async Task> CreateDocumentInfosAsync(DocumentChecksumsAndIds checksumsAndIds) { - using var _ = ArrayBuilder.GetInstance(checksumsAndIds.Length, out var documentInfos); + var documentInfos = new DocumentInfo[checksumsAndIds.Length]; + var index = 0; foreach (var (attributeChecksum, textChecksum, documentId) in checksumsAndIds) { cancellationToken.ThrowIfCancellationRequested(); - documentInfos.Add(await CreateDocumentInfoAsync(documentId, attributeChecksum, textChecksum, cancellationToken).ConfigureAwait(false)); + documentInfos[index++] = await CreateDocumentInfoAsync(documentId, attributeChecksum, textChecksum, cancellationToken).ConfigureAwait(false); } - return documentInfos.ToImmutableAndClear(); + return ImmutableCollectionsMarshal.AsImmutableArray(documentInfos); } } From 1b8970c882c32410d9236fe0f1ca0121fef0655d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:22:18 -0700 Subject: [PATCH 09/24] Parallel fetch --- .../Remote/Core/AbstractAssetProvider.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs index 22fdc549072c8..caf517bfd76b6 100644 --- a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs +++ b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs @@ -67,30 +67,30 @@ public async Task CreateProjectInfoAsync(ProjectStateChecksums proj var compilationOptions = attributes.FixUpCompilationOptions( await GetAssetAsync(new(AssetPathKind.ProjectCompilationOptions, projectId), projectChecksums.CompilationOptions, cancellationToken).ConfigureAwait(false)); - var parseOptions = await GetAssetAsync(new(AssetPathKind.ProjectParseOptions, projectId), projectChecksums.ParseOptions, cancellationToken).ConfigureAwait(false); + var parseOptionsTask = GetAssetAsync(new(AssetPathKind.ProjectParseOptions, projectId), projectChecksums.ParseOptions, cancellationToken); - var projectReferences = await this.GetAssetsArrayAsync(new(AssetPathKind.ProjectProjectReferences, projectId), projectChecksums.ProjectReferences, cancellationToken).ConfigureAwait(false); - var metadataReferences = await this.GetAssetsArrayAsync(new(AssetPathKind.ProjectMetadataReferences, projectId), projectChecksums.MetadataReferences, cancellationToken).ConfigureAwait(false); - var analyzerReferences = await this.GetAssetsArrayAsync(new(AssetPathKind.ProjectAnalyzerReferences, projectId), projectChecksums.AnalyzerReferences, cancellationToken).ConfigureAwait(false); + var projectReferencesTask = this.GetAssetsArrayAsync(new(AssetPathKind.ProjectProjectReferences, projectId), projectChecksums.ProjectReferences, cancellationToken); + var metadataReferencesTask = this.GetAssetsArrayAsync(new(AssetPathKind.ProjectMetadataReferences, projectId), projectChecksums.MetadataReferences, cancellationToken); + var analyzerReferencesTask = this.GetAssetsArrayAsync(new(AssetPathKind.ProjectAnalyzerReferences, projectId), projectChecksums.AnalyzerReferences, cancellationToken); // Attempt to fetch all the documents for this project in bulk. This will allow for all the data to be fetched // efficiently. We can then go and create the DocumentInfos for each document in the project. await SynchronizeProjectDocumentsAsync(projectChecksums, cancellationToken).ConfigureAwait(false); - var documentInfos = await CreateDocumentInfosAsync(projectChecksums.Documents).ConfigureAwait(false); - var additionalDocumentInfos = await CreateDocumentInfosAsync(projectChecksums.AdditionalDocuments).ConfigureAwait(false); - var analyzerConfigDocumentInfos = await CreateDocumentInfosAsync(projectChecksums.AnalyzerConfigDocuments).ConfigureAwait(false); + var documentInfosTask = CreateDocumentInfosAsync(projectChecksums.Documents); + var additionalDocumentInfosTask = CreateDocumentInfosAsync(projectChecksums.AdditionalDocuments); + var analyzerConfigDocumentInfosTask = CreateDocumentInfosAsync(projectChecksums.AnalyzerConfigDocuments); return ProjectInfo.Create( attributes, compilationOptions, - parseOptions, - documentInfos, - projectReferences, - metadataReferences, - analyzerReferences, - additionalDocumentInfos, - analyzerConfigDocumentInfos, + await parseOptionsTask.ConfigureAwait(false), + await documentInfosTask.ConfigureAwait(false), + await projectReferencesTask.ConfigureAwait(false), + await metadataReferencesTask.ConfigureAwait(false), + await analyzerReferencesTask.ConfigureAwait(false), + await additionalDocumentInfosTask.ConfigureAwait(false), + await analyzerConfigDocumentInfosTask.ConfigureAwait(false), hostObjectType: null); // TODO: https://github.com/dotnet/roslyn/issues/62804 async Task> CreateDocumentInfosAsync(DocumentChecksumsAndIds checksumsAndIds) From 2abb5455b12407bb4beafffb73f16ef6402a1469 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:24:03 -0700 Subject: [PATCH 10/24] Simplify --- src/Workspaces/Remote/Core/AbstractAssetProvider.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs index caf517bfd76b6..652ad566b191a 100644 --- a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs +++ b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs @@ -197,14 +197,14 @@ public static async Task> GetAssetsArrayAsync( using var _1 = PooledHashSet.GetInstance(out var checksumSet); checksumSet.AddAll(checksums.Children); - using var _2 = ArrayBuilder.GetInstance(checksumSet.Count, out var builder); + var builder = ImmutableArray.CreateBuilder(checksumSet.Count); - await assetProvider.GetAssetsAsync>( + await assetProvider.GetAssetHelper().GetAssetsAsync( assetPath, checksumSet, static (checksum, asset, builder) => builder.Add(asset), builder, cancellationToken).ConfigureAwait(false); - return builder.ToImmutableAndClear(); + return builder.MoveToImmutable(); } } From 8c79721497ba94e19af21b94304c3d73769fc3ca Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:25:30 -0700 Subject: [PATCH 11/24] simplify --- src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs b/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs index 4d484533e1850..7d68a08cc0e82 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs @@ -107,7 +107,7 @@ async ValueTask SynchronizeSolutionAssetsWorkerAsync() await Task.WhenAll(tasks).ConfigureAwait(false); using var _3 = ArrayBuilder.GetInstance(out var allProjectStateChecksums); - await this.GetAssetsAsync>( + await this.GetAssetHelper().GetAssetsAsync( AssetPathKind.ProjectStateChecksums, solutionStateChecksum.Projects.Checksums, static (_, asset, allProjectStateChecksums) => allProjectStateChecksums.Add(asset), From 2a83852ee021c7c0777113cce8da7977daaef560 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:27:45 -0700 Subject: [PATCH 12/24] simplify --- .../Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs index ae6756e6fefaa..a0151654cc002 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs @@ -267,8 +267,7 @@ await _assetProvider.GetAssetsAsync( assetPath: AssetPathKind.ProjectCompilationOptions, projectItemChecksums, cancellationToken).ConfigureAwait(false); } - using var _2 = ArrayBuilder.GetInstance(out var projectInfos); - using var _3 = ArrayBuilder.GetInstance(out var projectStateChecksumsToAdd); + using var _2 = ArrayBuilder.GetInstance(out var projectStateChecksumsToAdd); // added project foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) @@ -281,6 +280,7 @@ await _assetProvider.GetAssetsAsync( // efficiently in bulk and in parallel. await _assetProvider.SynchronizeProjectAssetsAsync(projectStateChecksumsToAdd, cancellationToken).ConfigureAwait(false); + using var _3 = ArrayBuilder.GetInstance(out var projectInfos); foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) { if (!oldProjectIdToStateChecksums.ContainsKey(projectId)) From a43348f5396f1b916555b0ce35fc3e7f0cddf47f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:28:49 -0700 Subject: [PATCH 13/24] simplify --- .../SourceGeneration/RemoteSourceGenerationService.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs b/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs index 6a974e5c64b6c..edea6958f1693 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Linq; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; @@ -37,15 +38,15 @@ protected override IRemoteSourceGenerationService CreateService(in ServiceConstr var project = solution.GetRequiredProject(projectId); var documentStates = await solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(project.State, cancellationToken).ConfigureAwait(false); - using var _ = ArrayBuilder<(SourceGeneratedDocumentIdentity documentIdentity, SourceGeneratedDocumentContentIdentity contentIdentity, DateTime generationDateTime)>.GetInstance(documentStates.Ids.Count, out var result); - + var result = new (SourceGeneratedDocumentIdentity documentIdentity, SourceGeneratedDocumentContentIdentity contentIdentity, DateTime generationDateTime)[documentStates.Ids.Count]; + var index = 0; foreach (var (id, state) in documentStates.States) { Contract.ThrowIfFalse(id.IsSourceGenerated); - result.Add((state.Identity, state.GetContentIdentity(), state.GenerationDateTime)); + result[index++] = (state.Identity, state.GetContentIdentity(), state.GenerationDateTime); } - return result.ToImmutableAndClear(); + return ImmutableCollectionsMarshal.AsImmutableArray(result); }, cancellationToken); } From 1260bead00951efd6b838c7aeb16c401d9710911 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:29:46 -0700 Subject: [PATCH 14/24] simplify --- .../SourceGeneration/RemoteSourceGenerationService.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs b/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs index edea6958f1693..6d7e72d98ef17 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs @@ -58,17 +58,17 @@ public ValueTask> GetContentsAsync( var project = solution.GetRequiredProject(projectId); var documentStates = await solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(project.State, cancellationToken).ConfigureAwait(false); - using var _ = ArrayBuilder.GetInstance(documentIds.Length, out var result); - + var result = new string[documentIds.Length]; + var index = 0; foreach (var id in documentIds) { Contract.ThrowIfFalse(id.IsSourceGenerated); var state = documentStates.GetRequiredState(id); var text = await state.GetTextAsync(cancellationToken).ConfigureAwait(false); - result.Add(text.ToString()); + result[index++] = text.ToString(); } - return result.ToImmutableAndClear(); + return ImmutableCollectionsMarshal.AsImmutableArray(result); }, cancellationToken); } From b6b607c64b37e3171407c07f4af0a6e70a0a75f8 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:30:44 -0700 Subject: [PATCH 15/24] Cleanup --- src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs b/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs index 7d68a08cc0e82..e754650d6939a 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs @@ -5,15 +5,12 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Serialization; -using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote; From 3d211efd5d8ebfdb9d73e91ecd64686eb2ca65e8 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:31:41 -0700 Subject: [PATCH 16/24] Cleanup --- .../Core/Portable/Workspace/Solution/StateChecksums.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs index 372b4d34a8072..2d37424a9e1fe 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs @@ -7,12 +7,10 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; From 89daf34a6e2869a3d2b754c96222feb77180464d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:36:17 -0700 Subject: [PATCH 17/24] In progresS --- .../Workspace/Solution/ChecksumsAndIds.cs | 45 +++++++++++++++++++ .../SolutionCompilationState_Checksum.cs | 4 +- .../Workspace/Solution/StateChecksums.cs | 16 +++---- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumsAndIds.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumsAndIds.cs index 474b4bb7e2f1a..6abc8ecfda663 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumsAndIds.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumsAndIds.cs @@ -80,6 +80,51 @@ public bool MoveNext() } } +internal readonly struct ProjectChecksumsAndIds +{ + public readonly ChecksumCollection Checksums; + public readonly ImmutableArray Ids; + + public ProjectChecksumsAndIds(ChecksumCollection checksums, ImmutableArray ids) + { + Contract.ThrowIfTrue(ids.Length != checksums.Children.Length); + + Checksums = checksums; + Ids = ids; + } + + public int Length => Ids.Length; + public Checksum Checksum => Checksums.Checksum; + + public void WriteTo(ObjectWriter writer) + { + this.Checksums.WriteTo(writer); + writer.WriteArray(this.Ids, static (writer, p) => p.WriteTo(writer)); + } + + public static ProjectChecksumsAndIds ReadFrom(ObjectReader reader) + { + return new( + ChecksumCollection.ReadFrom(reader), + reader.ReadArray(static reader => ProjectId.ReadFrom(reader))); + } + + public Enumerator GetEnumerator() + => new(this); + + public struct Enumerator(ProjectChecksumsAndIds checksumsAndIds) + { + private readonly ProjectChecksumsAndIds _checksumsAndIds = checksumsAndIds; + private int _index = -1; + + public bool MoveNext() + => ++_index < _checksumsAndIds.Length; + + public (Checksum checksum, ProjectId id) Current + => (_checksumsAndIds.Checksums.Children[_index], _checksumsAndIds.Ids[_index]); + } +} + internal readonly struct DocumentChecksumsAndIds { public readonly Checksum Checksum; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs index 134642f20beed..82600b5d6b1da 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs @@ -126,7 +126,7 @@ public async Task GetChecksumAsync(ProjectId projectId, CancellationTo } ChecksumCollection? frozenSourceGeneratedDocumentIdentities = null; - ChecksumsAndIds? frozenSourceGeneratedDocumentTexts = null; + DocumentChecksumsAndIds? frozenSourceGeneratedDocumentTexts = null; ImmutableArray frozenSourceGeneratedDocumentGenerationDateTimes = default; if (FrozenSourceGeneratedDocumentStates != null) @@ -135,7 +135,7 @@ public async Task GetChecksumAsync(ProjectId projectId, CancellationTo var identityChecksums = FrozenSourceGeneratedDocumentStates.SelectAsArray( static (s, arg) => arg.serializer.CreateChecksum(s.Identity, cancellationToken: arg.cancellationToken), (serializer, cancellationToken)); - frozenSourceGeneratedDocumentTexts = await FrozenSourceGeneratedDocumentStates.GetTextChecksumsAndIdsAsync(cancellationToken).ConfigureAwait(false); + frozenSourceGeneratedDocumentTexts = await FrozenSourceGeneratedDocumentStates.GetDocumentChecksumsAndIdsAsync(cancellationToken).ConfigureAwait(false); frozenSourceGeneratedDocumentIdentities = new ChecksumCollection(identityChecksums); frozenSourceGeneratedDocumentGenerationDateTimes = FrozenSourceGeneratedDocumentStates.SelectAsArray(d => d.GenerationDateTime); } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs index 2d37424a9e1fe..56b1d95918b17 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs @@ -22,7 +22,7 @@ public SolutionCompilationStateChecksums( Checksum solutionState, Checksum sourceGeneratorExecutionVersionMap, // These arrays are all the same length if present, and reference the same documents in the same order. - ChecksumsAndIds? frozenSourceGeneratedDocumentTexts, + DocumentChecksumsAndIds? frozenSourceGeneratedDocumentTexts, ChecksumCollection? frozenSourceGeneratedDocumentIdentities, ImmutableArray frozenSourceGeneratedDocumentGenerationDateTimes) { @@ -53,7 +53,7 @@ public SolutionCompilationStateChecksums( /// /// Checksums of the SourceTexts of the frozen documents directly. Not checksums of their DocumentStates. /// - public ChecksumsAndIds? FrozenSourceGeneratedDocumentTexts { get; } + public DocumentChecksumsAndIds? FrozenSourceGeneratedDocumentTexts { get; } public ChecksumCollection? FrozenSourceGeneratedDocumentIdentities { get; } // note: intentionally not part of the identity contract of this type. @@ -65,7 +65,7 @@ public void AddAllTo(HashSet checksums) checksums.AddIfNotNullChecksum(this.SolutionState); checksums.AddIfNotNullChecksum(this.SourceGeneratorExecutionVersionMap); this.FrozenSourceGeneratedDocumentIdentities?.AddAllTo(checksums); - this.FrozenSourceGeneratedDocumentTexts?.Checksums.AddAllTo(checksums); + this.FrozenSourceGeneratedDocumentTexts?.AddAllTo(checksums); } public void Serialize(ObjectWriter writer) @@ -92,13 +92,13 @@ public static SolutionCompilationStateChecksums Deserialize(ObjectReader reader) var sourceGeneratorExecutionVersionMap = Checksum.ReadFrom(reader); var hasFrozenSourceGeneratedDocuments = reader.ReadBoolean(); - ChecksumsAndIds? frozenSourceGeneratedDocumentTexts = null; + DocumentChecksumsAndIds? frozenSourceGeneratedDocumentTexts = null; ChecksumCollection? frozenSourceGeneratedDocumentIdentities = null; ImmutableArray frozenSourceGeneratedDocumentGenerationDateTimes = default; if (hasFrozenSourceGeneratedDocuments) { - frozenSourceGeneratedDocumentTexts = ChecksumsAndIds.ReadFrom(reader); + frozenSourceGeneratedDocumentTexts = DocumentChecksumsAndIds.ReadFrom(reader); frozenSourceGeneratedDocumentIdentities = ChecksumCollection.ReadFrom(reader); frozenSourceGeneratedDocumentGenerationDateTimes = reader.ReadArray(r => new DateTime(r.ReadInt64())); } @@ -205,7 +205,7 @@ await ChecksumCollection.FindAsync( internal sealed class SolutionStateChecksums( ProjectId? projectConeId, Checksum attributes, - ChecksumsAndIds projects, + ProjectChecksumsAndIds projects, ChecksumCollection analyzerReferences) { private ProjectCone? _projectCone; @@ -220,7 +220,7 @@ internal sealed class SolutionStateChecksums( public ProjectId? ProjectConeId { get; } = projectConeId; public Checksum Attributes { get; } = attributes; - public ChecksumsAndIds Projects { get; } = projects; + public ProjectChecksumsAndIds Projects { get; } = projects; public ChecksumCollection AnalyzerReferences { get; } = analyzerReferences; // Acceptably not threadsafe. ProjectCone is a class, and the runtime guarantees anyone will see this field fully @@ -258,7 +258,7 @@ public static SolutionStateChecksums Deserialize(ObjectReader reader) var result = new SolutionStateChecksums( projectConeId: reader.ReadBoolean() ? ProjectId.ReadFrom(reader) : null, attributes: Checksum.ReadFrom(reader), - projects: ChecksumsAndIds.ReadFrom(reader), + projects: ProjectChecksumsAndIds.ReadFrom(reader), analyzerReferences: ChecksumCollection.ReadFrom(reader)); Contract.ThrowIfFalse(result.Checksum == checksum); return result; From 64bcfbc0043c8215a3869d2fd1e2cdfd133cd119 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:37:32 -0700 Subject: [PATCH 18/24] In progresS --- .../Workspace/Solution/StateChecksums.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs index 56b1d95918b17..2b3138742a0e0 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs @@ -22,18 +22,18 @@ public SolutionCompilationStateChecksums( Checksum solutionState, Checksum sourceGeneratorExecutionVersionMap, // These arrays are all the same length if present, and reference the same documents in the same order. - DocumentChecksumsAndIds? frozenSourceGeneratedDocumentTexts, + DocumentChecksumsAndIds? frozenSourceGeneratedDocuments, ChecksumCollection? frozenSourceGeneratedDocumentIdentities, ImmutableArray frozenSourceGeneratedDocumentGenerationDateTimes) { // For the frozen source generated document info, we expect two either have both checksum collections or neither, and they // should both be the same length as there is a 1:1 correspondence between them. - Contract.ThrowIfFalse(frozenSourceGeneratedDocumentIdentities.HasValue == frozenSourceGeneratedDocumentTexts.HasValue); - Contract.ThrowIfFalse(frozenSourceGeneratedDocumentIdentities?.Count == frozenSourceGeneratedDocumentTexts?.Length); + Contract.ThrowIfFalse(frozenSourceGeneratedDocumentIdentities.HasValue == frozenSourceGeneratedDocuments.HasValue); + Contract.ThrowIfFalse(frozenSourceGeneratedDocumentIdentities?.Count == frozenSourceGeneratedDocuments?.Length); SolutionState = solutionState; SourceGeneratorExecutionVersionMap = sourceGeneratorExecutionVersionMap; - FrozenSourceGeneratedDocumentTexts = frozenSourceGeneratedDocumentTexts; + FrozenSourceGeneratedDocuments = frozenSourceGeneratedDocuments; FrozenSourceGeneratedDocumentIdentities = frozenSourceGeneratedDocumentIdentities; FrozenSourceGeneratedDocumentGenerationDateTimes = frozenSourceGeneratedDocumentGenerationDateTimes; @@ -43,7 +43,7 @@ public SolutionCompilationStateChecksums( SolutionState, SourceGeneratorExecutionVersionMap, FrozenSourceGeneratedDocumentIdentities?.Checksum ?? Checksum.Null, - frozenSourceGeneratedDocumentTexts?.Checksum ?? Checksum.Null); + frozenSourceGeneratedDocuments?.Checksum ?? Checksum.Null); } public Checksum Checksum { get; } @@ -53,7 +53,7 @@ public SolutionCompilationStateChecksums( /// /// Checksums of the SourceTexts of the frozen documents directly. Not checksums of their DocumentStates. /// - public DocumentChecksumsAndIds? FrozenSourceGeneratedDocumentTexts { get; } + public DocumentChecksumsAndIds? FrozenSourceGeneratedDocuments { get; } public ChecksumCollection? FrozenSourceGeneratedDocumentIdentities { get; } // note: intentionally not part of the identity contract of this type. @@ -65,7 +65,7 @@ public void AddAllTo(HashSet checksums) checksums.AddIfNotNullChecksum(this.SolutionState); checksums.AddIfNotNullChecksum(this.SourceGeneratorExecutionVersionMap); this.FrozenSourceGeneratedDocumentIdentities?.AddAllTo(checksums); - this.FrozenSourceGeneratedDocumentTexts?.AddAllTo(checksums); + this.FrozenSourceGeneratedDocuments?.AddAllTo(checksums); } public void Serialize(ObjectWriter writer) @@ -79,7 +79,7 @@ public void Serialize(ObjectWriter writer) writer.WriteBoolean(this.FrozenSourceGeneratedDocumentIdentities.HasValue); if (FrozenSourceGeneratedDocumentIdentities.HasValue) { - this.FrozenSourceGeneratedDocumentTexts!.Value.WriteTo(writer); + this.FrozenSourceGeneratedDocuments!.Value.WriteTo(writer); this.FrozenSourceGeneratedDocumentIdentities.Value.WriteTo(writer); writer.WriteArray(this.FrozenSourceGeneratedDocumentGenerationDateTimes, static (w, d) => w.WriteInt64(d.Ticks)); } @@ -136,7 +136,7 @@ public async Task FindAsync( if (compilationState.FrozenSourceGeneratedDocumentStates != null) { Contract.ThrowIfFalse(FrozenSourceGeneratedDocumentIdentities.HasValue); - Contract.ThrowIfFalse(FrozenSourceGeneratedDocumentTexts.HasValue); + Contract.ThrowIfFalse(FrozenSourceGeneratedDocuments.HasValue); // This could either be the checksum for the text (which we'll use our regular helper for first)... if (assetPath.IncludeSolutionFrozenSourceGeneratedDocumentText) @@ -154,7 +154,7 @@ await ChecksumCollection.FindAsync( if (documentId != null) { // If the caller is asking for a specific document, we can just look it up directly. - var index = FrozenSourceGeneratedDocumentTexts.Value.Ids.IndexOf(documentId); + var index = FrozenSourceGeneratedDocuments.Value.Ids.IndexOf(documentId); if (index >= 0) { var identityChecksum = FrozenSourceGeneratedDocumentIdentities.Value.Children[index]; @@ -173,7 +173,7 @@ await ChecksumCollection.FindAsync( var identityChecksum = FrozenSourceGeneratedDocumentIdentities.Value[0]; if (searchingChecksumsLeft.Remove(identityChecksum)) { - var id = FrozenSourceGeneratedDocumentTexts.Value.Ids[i]; + var id = FrozenSourceGeneratedDocuments.Value.Ids[i]; Contract.ThrowIfFalse(compilationState.FrozenSourceGeneratedDocumentStates.TryGetState(id, out var state)); result[identityChecksum] = state.Identity; } From bcc5362af66e60abea106561f7078942f7bed342 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:38:54 -0700 Subject: [PATCH 19/24] In progresS --- .../ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs index a0151654cc002..3f417f6d07f0c 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs @@ -88,18 +88,18 @@ public async Task CreateSolutionAsync(Checksum newSolutionChecksum, Ca } if (newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentIdentities.HasValue && - newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentTexts.HasValue && + newSolutionCompilationChecksums.FrozenSourceGeneratedDocuments.HasValue && !newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentGenerationDateTimes.IsDefault) { var newSolutionFrozenSourceGeneratedDocumentIdentities = newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentIdentities.Value; - var newSolutionFrozenSourceGeneratedDocumentTexts = newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentTexts.Value; - var count = newSolutionFrozenSourceGeneratedDocumentTexts.Checksums.Count; + var newSolutionFrozenSourceGeneratedDocuments = newSolutionCompilationChecksums.FrozenSourceGeneratedDocuments.Value; + var count = newSolutionFrozenSourceGeneratedDocuments.Ids.Length; using var _ = ArrayBuilder<(SourceGeneratedDocumentIdentity identity, DateTime generationDateTime, SourceText text)>.GetInstance(count, out var frozenDocuments); for (var i = 0; i < count; i++) { - var frozenDocumentId = newSolutionFrozenSourceGeneratedDocumentTexts.Ids[i]; - var frozenDocumentTextChecksum = newSolutionFrozenSourceGeneratedDocumentTexts.Checksums[i]; + var frozenDocumentId = newSolutionFrozenSourceGeneratedDocuments.Ids[i]; + var frozenDocumentTextChecksum = newSolutionFrozenSourceGeneratedDocuments.TextChecksums[i]; var frozenDocumentIdentity = newSolutionFrozenSourceGeneratedDocumentIdentities[i]; var identity = await _assetProvider.GetAssetAsync( From 831e391cf5722323eb7f1964e21f20a928a9cd66 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:44:29 -0700 Subject: [PATCH 20/24] simplify --- .../Test.Next/Remote/SerializationValidator.cs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs b/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs index b8f4c75cf1aae..c7f9578ffe043 100644 --- a/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs +++ b/src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs @@ -222,13 +222,6 @@ internal async Task VerifySolutionStateSerializationAsync(Solution solution, Che SolutionStateEqual(solutionObjectFromSolution, solutionObjectFromSyncObject); } - private static void AssertChecksumCollectionEqual( - ChecksumsAndIds collection1, ChecksumsAndIds collection2) - { - AssertChecksumCollectionEqual(collection1.Checksums, collection2.Checksums); - AssertEx.Equal(collection1.Ids, collection2.Ids); - } - private static void AssertChecksumCollectionEqual( ChecksumCollection collection1, ChecksumCollection collection2) { @@ -252,16 +245,17 @@ internal void SolutionCompilationStateEqual(SolutionCompilationStateChecksums so if (solutionObject1.FrozenSourceGeneratedDocumentIdentities.HasValue) AssertChecksumCollectionEqual(solutionObject1.FrozenSourceGeneratedDocumentIdentities.Value, solutionObject2.FrozenSourceGeneratedDocumentIdentities!.Value); - Assert.Equal(solutionObject1.FrozenSourceGeneratedDocumentTexts.HasValue, solutionObject2.FrozenSourceGeneratedDocumentTexts.HasValue); - if (solutionObject1.FrozenSourceGeneratedDocumentTexts.HasValue) - AssertChecksumCollectionEqual(solutionObject1.FrozenSourceGeneratedDocumentTexts.Value, solutionObject2.FrozenSourceGeneratedDocumentTexts!.Value); + Assert.Equal(solutionObject1.FrozenSourceGeneratedDocuments.HasValue, solutionObject2.FrozenSourceGeneratedDocuments.HasValue); + if (solutionObject1.FrozenSourceGeneratedDocuments.HasValue) + AssertDocumentChecksumCollectionEqual(solutionObject1.FrozenSourceGeneratedDocuments.Value, solutionObject2.FrozenSourceGeneratedDocuments!.Value); } internal void SolutionStateEqual(SolutionStateChecksums solutionObject1, SolutionStateChecksums solutionObject2) { Assert.Equal(solutionObject1.Checksum, solutionObject2.Checksum); Assert.Equal(solutionObject1.Attributes, solutionObject2.Attributes); - AssertChecksumCollectionEqual(solutionObject1.Projects, solutionObject2.Projects); + AssertEx.Equals(solutionObject1.Projects.Ids, solutionObject2.Projects.Ids); + AssertChecksumCollectionEqual(solutionObject1.Projects.Checksums, solutionObject2.Projects.Checksums); AssertChecksumCollectionEqual(solutionObject1.AnalyzerReferences, solutionObject2.AnalyzerReferences); ProjectStatesEqual(ToProjectObjects(solutionObject1.Projects.Checksums), ToProjectObjects(solutionObject2.Projects.Checksums)); From e2c3814ecfa4f647c9061daaff25a621ce9aaa3c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:45:10 -0700 Subject: [PATCH 21/24] remove unused --- .../Workspace/Solution/TextDocumentStates.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs index be4f6772f7905..e15b39a1d1a67 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs @@ -305,21 +305,6 @@ static async (state, _, cancellationToken) => await state.GetChecksumAsync(cance return new(documentChecksums, SelectAsArray(static s => s.Id)); } - public async ValueTask> GetTextChecksumsAndIdsAsync(CancellationToken cancellationToken) - { - var documentTextChecksums = await SelectAsArrayAsync( - static async (state, _, cancellationToken) => - { - var stateChecksums = await state.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - return stateChecksums.Text; - }, - arg: default(VoidResult), - cancellationToken).ConfigureAwait(false); - - var documentChecksums = new ChecksumCollection(documentTextChecksums); - return new(documentChecksums, SelectAsArray(static s => s.Id)); - } - public async ValueTask GetDocumentChecksumsAndIdsAsync(CancellationToken cancellationToken) { var attributeChecksums = new Checksum[_map.Count]; From b130c8f8beea0f47b8f35f4c2bab2f9cfabb1321 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 11:48:14 -0700 Subject: [PATCH 22/24] Separate types --- .../Workspace/Solution/ChecksumsAndIds.cs | 80 +++---------------- ...eneratedFileReplacingCompilationTracker.cs | 2 +- .../Workspace/Solution/TextDocumentStates.cs | 11 --- 3 files changed, 10 insertions(+), 83 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumsAndIds.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumsAndIds.cs index 6abc8ecfda663..23b49cca4c0dc 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumsAndIds.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ChecksumsAndIds.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -11,75 +10,9 @@ namespace Microsoft.CodeAnalysis.Serialization; /// -/// A paired list of IDs (either s or s), and the checksums for their -/// corresponding s or s). +/// A paired list of s, and the checksums for their corresponding 's . /// -internal readonly struct ChecksumsAndIds -{ - public readonly ChecksumCollection Checksums; - public readonly ImmutableArray Ids; - - private static readonly Func s_readId; - private static readonly Action s_writeTo; - - static ChecksumsAndIds() - { - if (typeof(TId) == typeof(ProjectId)) - { - s_readId = reader => (TId)(object)ProjectId.ReadFrom(reader); - s_writeTo = (writer, id) => ((ProjectId)(object)id!).WriteTo(writer); - } - else if (typeof(TId) == typeof(DocumentId)) - { - s_readId = reader => (TId)(object)DocumentId.ReadFrom(reader); - s_writeTo = (writer, id) => ((DocumentId)(object)id!).WriteTo(writer); - } - else - { - throw ExceptionUtilities.Unreachable(); - } - } - - public ChecksumsAndIds(ChecksumCollection checksums, ImmutableArray ids) - { - Contract.ThrowIfTrue(ids.Length != checksums.Children.Length); - - Checksums = checksums; - Ids = ids; - } - - public int Length => Ids.Length; - public Checksum Checksum => Checksums.Checksum; - - public void WriteTo(ObjectWriter writer) - { - this.Checksums.WriteTo(writer); - writer.WriteArray(this.Ids, s_writeTo); - } - - public static ChecksumsAndIds ReadFrom(ObjectReader reader) - { - return new( - ChecksumCollection.ReadFrom(reader), - reader.ReadArray(s_readId)); - } - - public Enumerator GetEnumerator() - => new(this); - - public struct Enumerator(ChecksumsAndIds checksumsAndIds) - { - private readonly ChecksumsAndIds _checksumsAndIds = checksumsAndIds; - private int _index = -1; - - public bool MoveNext() - => ++_index < _checksumsAndIds.Length; - - public (Checksum checksum, TId id) Current - => (_checksumsAndIds.Checksums.Children[_index], _checksumsAndIds.Ids[_index]); - } -} - internal readonly struct ProjectChecksumsAndIds { public readonly ChecksumCollection Checksums; @@ -120,11 +53,16 @@ public struct Enumerator(ProjectChecksumsAndIds checksumsAndIds) public bool MoveNext() => ++_index < _checksumsAndIds.Length; - public (Checksum checksum, ProjectId id) Current + public readonly (Checksum checksum, ProjectId id) Current => (_checksumsAndIds.Checksums.Children[_index], _checksumsAndIds.Ids[_index]); } } +/// +/// A paired list of s, and the checksums for their corresponding 's and checksums. +/// internal readonly struct DocumentChecksumsAndIds { public readonly Checksum Checksum; @@ -178,7 +116,7 @@ public struct Enumerator(DocumentChecksumsAndIds checksumsAndIds) public bool MoveNext() => ++_index < _checksumsAndIds.Length; - public (Checksum attributeChecksum, Checksum textChecksum, DocumentId id) Current + public readonly (Checksum attributeChecksum, Checksum textChecksum, DocumentId id) Current => (_checksumsAndIds.AttributeChecksums.Children[_index], _checksumsAndIds.TextChecksums.Children[_index], _checksumsAndIds.Ids[_index]); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.GeneratedFileReplacingCompilationTracker.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.GeneratedFileReplacingCompilationTracker.cs index 6f225f909ac20..990d4467db2a7 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.GeneratedFileReplacingCompilationTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.GeneratedFileReplacingCompilationTracker.cs @@ -145,7 +145,7 @@ public Task GetDependentChecksumAsync(SolutionCompilationState compila private async Task ComputeDependentChecksumAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken) => Checksum.Create( await UnderlyingTracker.GetDependentChecksumAsync(compilationState, cancellationToken).ConfigureAwait(false), - (await _replacementDocumentStates.GetChecksumsAndIdsAsync(cancellationToken).ConfigureAwait(false)).Checksum); + (await _replacementDocumentStates.GetDocumentChecksumsAndIdsAsync(cancellationToken).ConfigureAwait(false)).Checksum); public MetadataReference? GetPartialMetadataReference(ProjectState fromProject, ProjectReference projectReference) { diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs index e15b39a1d1a67..09e672892f944 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs @@ -294,17 +294,6 @@ public int Compare(DocumentId? x, DocumentId? y) } } - public async ValueTask> GetChecksumsAndIdsAsync(CancellationToken cancellationToken) - { - var documentTextChecksums = await SelectAsArrayAsync( - static async (state, _, cancellationToken) => await state.GetChecksumAsync(cancellationToken).ConfigureAwait(false), - arg: default(VoidResult), - cancellationToken).ConfigureAwait(false); - - var documentChecksums = new ChecksumCollection(documentTextChecksums); - return new(documentChecksums, SelectAsArray(static s => s.Id)); - } - public async ValueTask GetDocumentChecksumsAndIdsAsync(CancellationToken cancellationToken) { var attributeChecksums = new Checksum[_map.Count]; From 58206dd1eee1147733c30e0c2ab60af619529308 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 13:44:12 -0700 Subject: [PATCH 23/24] Simplify more --- .../Workspace/Solution/TextDocumentStates.cs | 44 +++++-------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs index 09e672892f944..21e522eb393c7 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs @@ -111,42 +111,18 @@ public IEnumerable GetStatesInCompilationOrder() } public ImmutableArray SelectAsArray(Func selector) - { - // Directly use ImmutableArray.Builder as we know the final size - var builder = ImmutableArray.CreateBuilder(_map.Count); - - foreach (var (_, state) in _map) - { - builder.Add(selector(state)); - } - - return builder.MoveToImmutable(); - } + => SelectAsArray( + static (state, selector) => selector(state), + selector); public ImmutableArray SelectAsArray(Func selector, TArg arg) { - // Directly use ImmutableArray.Builder as we know the final size - var builder = ImmutableArray.CreateBuilder(_map.Count); - - foreach (var (_, state) in _map) - { - builder.Add(selector(state, arg)); - } - - return builder.MoveToImmutable(); - } - - public async ValueTask> SelectAsArrayAsync(Func> selector, TArg arg, CancellationToken cancellationToken) - { - // Directly use ImmutableArray.Builder as we know the final size - var builder = ImmutableArray.CreateBuilder(_map.Count); - + var result = new TValue[_map.Count]; + var index = 0; foreach (var (_, state) in _map) - { - builder.Add(await selector(state, arg, cancellationToken).ConfigureAwait(true)); - } + result[index++] = selector(state, arg); - return builder.MoveToImmutable(); + return ImmutableCollectionsMarshal.AsImmutableArray(result); } public TextDocumentStates AddRange(ImmutableArray states) @@ -298,20 +274,22 @@ public async ValueTask GetDocumentChecksumsAndIdsAsync( { var attributeChecksums = new Checksum[_map.Count]; var textChecksums = new Checksum[_map.Count]; + var documentIds = new DocumentId[_map.Count]; var index = 0; - foreach (var (_, state) in _map) + foreach (var (documentId, state) in _map) { var stateChecksums = await state.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); attributeChecksums[index] = stateChecksums.Info; textChecksums[index] = stateChecksums.Text; + documentIds[index] = documentId; index++; } return new( new ChecksumCollection(ImmutableCollectionsMarshal.AsImmutableArray(attributeChecksums)), new ChecksumCollection(ImmutableCollectionsMarshal.AsImmutableArray(textChecksums)), - SelectAsArray(static s => s.Id)); + ImmutableCollectionsMarshal.AsImmutableArray(documentIds)); } public void AddDocumentIdsWithFilePath(ref TemporaryArray temporaryArray, string filePath) From 6eb6457982510d6ef0b0f062289df2eb335822ff Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Apr 2024 13:49:25 -0700 Subject: [PATCH 24/24] Update src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs --- .../Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs index 3f417f6d07f0c..ca3315194f902 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs @@ -280,7 +280,7 @@ await _assetProvider.GetAssetsAsync( // efficiently in bulk and in parallel. await _assetProvider.SynchronizeProjectAssetsAsync(projectStateChecksumsToAdd, cancellationToken).ConfigureAwait(false); - using var _3 = ArrayBuilder.GetInstance(out var projectInfos); + using var _3 = ArrayBuilder.GetInstance(projectStateChecksumsToAdd.Count, out var projectInfos); foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) { if (!oldProjectIdToStateChecksums.ContainsKey(projectId))