Skip to content

Commit

Permalink
Merge pull request #74857 from CyrusNajmabadi/moveType
Browse files Browse the repository at this point in the history
  • Loading branch information
CyrusNajmabadi authored Aug 22, 2024
2 parents 8e98fc9 + 36435da commit 95794a1
Show file tree
Hide file tree
Showing 54 changed files with 4,391 additions and 4,447 deletions.
49 changes: 15 additions & 34 deletions src/Workspaces/Core/Portable/Serialization/SerializerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,67 +4,48 @@

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Versioning;
using System.Threading;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Serialization;

#if NETCOREAPP
[SupportedOSPlatform("windows")]
#endif
internal partial class SerializerService : ISerializerService
[method: Obsolete(MefConstruction.FactoryMethodMessage, error: true)]
internal partial class SerializerService(SolutionServices workspaceServices) : ISerializerService
{
[ExportWorkspaceServiceFactory(typeof(ISerializerService), layer: ServiceLayer.Default), Shared]
internal sealed class Factory : IWorkspaceServiceFactory
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class Factory() : IWorkspaceServiceFactory
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public Factory()
{
}

[Obsolete(MefConstruction.FactoryMethodMessage, error: true)]
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
=> new SerializerService(workspaceServices.SolutionServices);
}

private static readonly Func<WellKnownSynchronizationKind, string> s_logKind = k => k.ToString();

private readonly SolutionServices _workspaceServices;

private readonly Lazy<TemporaryStorageService> _storageService;
private readonly ITextFactoryService _textService;
private readonly IDocumentationProviderService? _documentationService;
private readonly IAnalyzerAssemblyLoaderProvider _analyzerLoaderProvider;
// Serialization to temporary storage is only involved when we have a remote process. Which is only in VS. So the
// type of the storage service here is well known. However the serializer is created in other cases (e.g. to
// compute project state checksums). So lazily instantiate the storage service to avoid attempting to get the
// TemporaryStorageService when not available.

private readonly ConcurrentDictionary<string, IOptionsSerializationService> _lazyLanguageSerializationService;
private readonly Lazy<TemporaryStorageService> _storageService = new(() => (TemporaryStorageService)workspaceServices.GetRequiredService<ITemporaryStorageServiceInternal>());
private readonly ITextFactoryService _textService = workspaceServices.GetRequiredService<ITextFactoryService>();
private readonly IDocumentationProviderService? _documentationService = workspaceServices.GetService<IDocumentationProviderService>();
private readonly IAnalyzerAssemblyLoaderProvider _analyzerLoaderProvider = workspaceServices.GetRequiredService<IAnalyzerAssemblyLoaderProvider>();

[Obsolete(MefConstruction.FactoryMethodMessage, error: true)]
private protected SerializerService(SolutionServices workspaceServices)
{
_workspaceServices = workspaceServices;

// Serialization to temporary storage is only involved when we have a remote process. Which is only in VS. So the type of the
// storage service here is well known. However the serializer is created in other cases (e.g. to compute project state checksums).
// So lazily instantiate the storage service to avoid attempting to get the TemporaryStorageService when not available.
_storageService = new Lazy<TemporaryStorageService>(() => (TemporaryStorageService)workspaceServices.GetRequiredService<ITemporaryStorageServiceInternal>());
_textService = workspaceServices.GetRequiredService<ITextFactoryService>();
_analyzerLoaderProvider = workspaceServices.GetRequiredService<IAnalyzerAssemblyLoaderProvider>();
_documentationService = workspaceServices.GetService<IDocumentationProviderService>();

_lazyLanguageSerializationService = new ConcurrentDictionary<string, IOptionsSerializationService>(concurrencyLevel: 2, capacity: _workspaceServices.SupportedLanguages.Count());
}
private readonly ConcurrentDictionary<string, IOptionsSerializationService> _lazyLanguageSerializationService = new(concurrencyLevel: 2, capacity: workspaceServices.SupportedLanguages.Count());

public Checksum CreateChecksum(object value, CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -280,7 +261,7 @@ public object Deserialize(WellKnownSynchronizationKind kind, ObjectReader reader
}

private IOptionsSerializationService GetOptionsSerializationService(string languageName)
=> _lazyLanguageSerializationService.GetOrAdd(languageName, n => _workspaceServices.GetLanguageServices(n).GetRequiredService<IOptionsSerializationService>());
=> _lazyLanguageSerializationService.GetOrAdd(languageName, n => workspaceServices.GetLanguageServices(n).GetRequiredService<IOptionsSerializationService>());

public Checksum CreateParseOptionsChecksum(ParseOptions value)
=> Checksum.Create((value, @this: this), static (tuple, writer) => tuple.@this.SerializeParseOptions(tuple.value, writer));
Expand Down
67 changes: 0 additions & 67 deletions src/Workspaces/Remote/Core/AbstractAssetProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,70 +162,3 @@ public Task GetAssetsAsync<TArg>(AssetPath assetPath, ChecksumCollection checksu
=> assetProvider.GetAssetsAsync(assetPath, checksums, callback, arg, cancellationToken);
}
}

internal static class AbstractAssetProviderExtensions
{
public static Task GetAssetsAsync<TAsset>(
this AbstractAssetProvider assetProvider, AssetPath assetPath, HashSet<Checksum> checksums, CancellationToken cancellationToken)
{
return assetProvider.GetAssetsAsync<TAsset, VoidResult>(
assetPath, checksums, callback: null, arg: default, cancellationToken);
}

public static Task GetAssetsAsync<T>(
this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, CancellationToken cancellationToken)
{
return assetProvider.GetAssetsAsync<T, VoidResult>(
assetPath, checksums, callback: null, arg: default, cancellationToken);
}

public static async Task GetAssetsAsync<T, TArg>(
this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, Action<Checksum, T, TArg>? callback, TArg? arg, CancellationToken cancellationToken)
{
using var _1 = PooledHashSet<Checksum>.GetInstance(out var checksumSet);
#if NET
checksumSet.EnsureCapacity(checksums.Children.Length);
#endif
checksumSet.AddAll(checksums.Children);

await assetProvider.GetAssetsAsync(assetPath, checksumSet, callback, arg, cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Returns an array of assets, corresponding to all the checksums found in the given <paramref name="checksums"/>.
/// The assets will be returned in the order corresponding to their checksum in <paramref name="checksums"/>.
/// </summary>
public static async Task<ImmutableArray<T>> GetAssetsArrayAsync<T>(
this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, CancellationToken cancellationToken) where T : class
{
// Note: nothing stops 'checksums' from having multiple identical checksums in it. First, collapse this down to
// a set so we're only asking about unique checksums.
using var _1 = PooledHashSet<Checksum>.GetInstance(out var checksumSet);
#if NET
checksumSet.EnsureCapacity(checksums.Children.Length);
#endif
checksumSet.AddAll(checksums.Children);

using var _2 = PooledDictionary<Checksum, T>.GetInstance(out var checksumToAsset);

await assetProvider.GetAssetHelper<T>().GetAssetsAsync(
assetPath, checksumSet,
// Calling .Add here is safe. As checksum-set is a unique set of checksums, we'll never have collions here.
static (checksum, asset, checksumToAsset) => checksumToAsset.Add(checksum, asset),
checksumToAsset,
cancellationToken).ConfigureAwait(false);

// Note: GetAssetsAsync will only succeed if we actually found all our assets (it crashes otherwise). So we can
// just safely assume we can index into checksumToAsset here.
Contract.ThrowIfTrue(checksumToAsset.Count != checksumSet.Count);

// The result of GetAssetsArrayAsync wants the returned assets to be in the exact order of the checksums that
// were in 'checksums'. So now fetch the assets in that order, even if we found them in an entirely different
// order.
var result = new FixedSizeArrayBuilder<T>(checksums.Children.Length);
foreach (var checksum in checksums.Children)
result.Add(checksumToAsset[checksum]);

return result.MoveToImmutable();
}
}
81 changes: 81 additions & 0 deletions src/Workspaces/Remote/Core/AbstractAssetProviderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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 System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Serialization;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Remote;

internal static class AbstractAssetProviderExtensions
{
public static Task GetAssetsAsync<TAsset>(
this AbstractAssetProvider assetProvider, AssetPath assetPath, HashSet<Checksum> checksums, CancellationToken cancellationToken)
{
return assetProvider.GetAssetsAsync<TAsset, VoidResult>(
assetPath, checksums, callback: null, arg: default, cancellationToken);
}

public static Task GetAssetsAsync<T>(
this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, CancellationToken cancellationToken)
{
return assetProvider.GetAssetsAsync<T, VoidResult>(
assetPath, checksums, callback: null, arg: default, cancellationToken);
}

public static async Task GetAssetsAsync<T, TArg>(
this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, Action<Checksum, T, TArg>? callback, TArg? arg, CancellationToken cancellationToken)
{
using var _1 = PooledHashSet<Checksum>.GetInstance(out var checksumSet);
#if NET
checksumSet.EnsureCapacity(checksums.Children.Length);
#endif
checksumSet.AddAll(checksums.Children);

await assetProvider.GetAssetsAsync(assetPath, checksumSet, callback, arg, cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Returns an array of assets, corresponding to all the checksums found in the given <paramref name="checksums"/>.
/// The assets will be returned in the order corresponding to their checksum in <paramref name="checksums"/>.
/// </summary>
public static async Task<ImmutableArray<T>> GetAssetsArrayAsync<T>(
this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, CancellationToken cancellationToken) where T : class
{
// Note: nothing stops 'checksums' from having multiple identical checksums in it. First, collapse this down to
// a set so we're only asking about unique checksums.
using var _1 = PooledHashSet<Checksum>.GetInstance(out var checksumSet);
#if NET
checksumSet.EnsureCapacity(checksums.Children.Length);
#endif
checksumSet.AddAll(checksums.Children);

using var _2 = PooledDictionary<Checksum, T>.GetInstance(out var checksumToAsset);

await assetProvider.GetAssetHelper<T>().GetAssetsAsync(
assetPath, checksumSet,
// Calling .Add here is safe. As checksum-set is a unique set of checksums, we'll never have collions here.
static (checksum, asset, checksumToAsset) => checksumToAsset.Add(checksum, asset),
checksumToAsset,
cancellationToken).ConfigureAwait(false);

// Note: GetAssetsAsync will only succeed if we actually found all our assets (it crashes otherwise). So we can
// just safely assume we can index into checksumToAsset here.
Contract.ThrowIfTrue(checksumToAsset.Count != checksumSet.Count);

// The result of GetAssetsArrayAsync wants the returned assets to be in the exact order of the checksums that
// were in 'checksums'. So now fetch the assets in that order, even if we found them in an entirely different
// order.
var result = new FixedSizeArrayBuilder<T>(checksums.Children.Length);
foreach (var checksum in checksums.Children)
result.Add(checksumToAsset[checksum]);

return result.MoveToImmutable();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,20 @@
using Microsoft.CodeAnalysis.Remote;
using Microsoft.ServiceHub.Framework;

namespace Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api
namespace Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api;

internal static class PythiaBrokeredServiceImplementation
{
internal static class PythiaBrokeredServiceImplementation
{
public static ValueTask<T> RunServiceAsync<T>(Func<CancellationToken, ValueTask<T>> implementation, CancellationToken cancellationToken)
=> BrokeredServiceBase.RunServiceImplAsync<T>(implementation, cancellationToken);
public static ValueTask<T> RunServiceAsync<T>(Func<CancellationToken, ValueTask<T>> implementation, CancellationToken cancellationToken)
=> BrokeredServiceBase.RunServiceImplAsync<T>(implementation, cancellationToken);

public static ValueTask RunServiceAsync(Func<CancellationToken, ValueTask> implementation, CancellationToken cancellationToken)
=> BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken);
public static ValueTask RunServiceAsync(Func<CancellationToken, ValueTask> implementation, CancellationToken cancellationToken)
=> BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken);

[Obsolete("Use RunServiceAsync (that is passsed a Solution) instead", error: false)]
public static ValueTask<Solution> GetSolutionAsync(this PythiaPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, CancellationToken cancellationToken)
=> RemoteWorkspaceManager.Default.GetSolutionAsync(client, solutionInfo.UnderlyingObject, cancellationToken);
[Obsolete("Use RunServiceAsync (that is passsed a Solution) instead", error: false)]
public static ValueTask<Solution> GetSolutionAsync(this PythiaPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, CancellationToken cancellationToken)
=> RemoteWorkspaceManager.Default.GetSolutionAsync(client, solutionInfo.UnderlyingObject, cancellationToken);

public static ValueTask<T> RunServiceAsync<T>(this PythiaPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, Func<Solution, ValueTask<T>> implementation, CancellationToken cancellationToken)
=> RemoteWorkspaceManager.Default.RunServiceAsync(client, solutionInfo.UnderlyingObject, implementation, cancellationToken);
}
public static ValueTask<T> RunServiceAsync<T>(this PythiaPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, Func<Solution, ValueTask<T>> implementation, CancellationToken cancellationToken)
=> RemoteWorkspaceManager.Default.RunServiceAsync(client, solutionInfo.UnderlyingObject, implementation, cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,19 @@
using Microsoft.CodeAnalysis.Remote;
using Microsoft.ServiceHub.Framework;

namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Api
namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Api;

internal static class RazorBrokeredServiceImplementation
{
internal static class RazorBrokeredServiceImplementation
{
public static ValueTask<T> RunServiceAsync<T>(Func<CancellationToken, ValueTask<T>> implementation, CancellationToken cancellationToken)
=> BrokeredServiceBase.RunServiceImplAsync<T>(implementation, cancellationToken);
public static ValueTask<T> RunServiceAsync<T>(Func<CancellationToken, ValueTask<T>> implementation, CancellationToken cancellationToken)
=> BrokeredServiceBase.RunServiceImplAsync<T>(implementation, cancellationToken);

public static ValueTask RunServiceAsync(Func<CancellationToken, ValueTask> implementation, CancellationToken cancellationToken)
=> BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken);
public static ValueTask RunServiceAsync(Func<CancellationToken, ValueTask> implementation, CancellationToken cancellationToken)
=> BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken);

public static ValueTask<T> RunServiceAsync<T>(this RazorPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, Func<Solution, ValueTask<T>> implementation, CancellationToken cancellationToken)
=> RemoteWorkspaceManager.Default.RunServiceAsync(client, solutionInfo.UnderlyingObject, implementation, cancellationToken);
public static ValueTask<T> RunServiceAsync<T>(this RazorPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, Func<Solution, ValueTask<T>> implementation, CancellationToken cancellationToken)
=> RemoteWorkspaceManager.Default.RunServiceAsync(client, solutionInfo.UnderlyingObject, implementation, cancellationToken);

public static Workspace GetWorkspace()
=> RemoteWorkspaceManager.Default.GetWorkspace();
}
public static Workspace GetWorkspace()
=> RemoteWorkspaceManager.Default.GetWorkspace();
}
Loading

0 comments on commit 95794a1

Please # to comment.