提交 6fc9f5ae 编写于 作者: C CyrusNajmabadi

Merge pull request #7816 from CyrusNajmabadi/symbolTreeInfoCaching

Only allow one client to produce a symbol tree info at a time.
......@@ -973,6 +973,13 @@ IEnumerable<IModuleSymbol> IAssemblySymbol.Modules
}
}
/// <summary>
/// If this symbol represents a metadata assembly returns the underlying <see cref="AssemblyMetadata"/>.
///
/// Otherwise, this returns <code>null</code>.
/// </summary>
public abstract AssemblyMetadata GetMetadata();
INamedTypeSymbol IAssemblySymbol.ResolveForwardedType(string fullyQualifiedMetadataName)
{
return ResolveForwardedType(fullyQualifiedMetadataName);
......
......@@ -248,5 +248,7 @@ internal PEModuleSymbol PrimaryModule
{
get { return null; }
}
public override AssemblyMetadata GetMetadata() => _assembly.GetNonDisposableMetadata();
}
}
......@@ -682,5 +682,7 @@ internal IEnumerable<NamedTypeSymbol> GetForwardedTypes()
yield return assemblySymbol.LookupTopLevelMetadataType(ref name, digThroughForwardedTypes: true);
}
}
public override ModuleMetadata GetMetadata() => _module.GetNonDisposableMetadata();
}
}
......@@ -184,5 +184,7 @@ public override bool MightContainExtensionMethods
return false;
}
}
public override AssemblyMetadata GetMetadata() => null;
}
}
......@@ -183,6 +183,8 @@ internal override bool HasAssemblyRuntimeCompatibilityAttribute
{
get { return null; }
}
public override ModuleMetadata GetMetadata() => null;
}
internal class MissingModuleSymbolWithName : MissingModuleSymbol
......
......@@ -377,6 +377,13 @@ public override TResult Accept<TResult>(SymbolVisitor<TResult> visitor)
return visitor.VisitModule(this);
}
/// <summary>
/// If this symbol represents a metadata module returns the underlying <see cref="ModuleMetadata"/>.
///
/// Otherwise, this returns <code>null</code>.
/// </summary>
public abstract ModuleMetadata GetMetadata();
#endregion
}
}
......@@ -284,5 +284,7 @@ internal override NamedTypeSymbol TryLookupForwardedMetadataTypeWithCycleDetecti
return this.RetargetingTranslator.Retarget(underlying, RetargetOptions.RetargetPrimitiveTypesByName);
}
public override AssemblyMetadata GetMetadata() => _underlyingAssembly.GetMetadata();
}
}
}
\ No newline at end of file
......@@ -282,5 +282,7 @@ internal override bool HasAssemblyRuntimeCompatibilityAttribute
{
get { return null; }
}
public override ModuleMetadata GetMetadata() => _underlyingModule.GetMetadata();
}
}
}
\ No newline at end of file
......@@ -2557,5 +2557,7 @@ internal override NamedTypeSymbol TryLookupForwardedMetadataTypeWithCycleDetecti
return null;
}
public override AssemblyMetadata GetMetadata() => null;
}
}
}
\ No newline at end of file
......@@ -7,7 +7,6 @@
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
......@@ -555,5 +554,7 @@ internal override bool HasAssemblyRuntimeCompatibilityAttribute
return data != null && data.HasDefaultCharSetAttribute ? data.DefaultCharacterSet : (CharSet?)null;
}
}
public override ModuleMetadata GetMetadata() => null;
}
}
......@@ -104,5 +104,7 @@ internal override NamedTypeSymbol TryLookupForwardedMetadataTypeWithCycleDetecti
{
return null;
}
public override AssemblyMetadata GetMetadata() => null;
}
}
......@@ -40,7 +40,10 @@ internal sealed class PEAssembly
private ThreeState _lazyDeclaresTheObjectClass;
// We need to store reference for to keep the metadata alive while symbols have reference to PEAssembly.
/// <summary>
/// We need to store reference to the assembly metadata to keep the metadata alive while
/// symbols have reference to PEAssembly.
/// </summary>
private readonly AssemblyMetadata _owner;
//Maps from simple name to list of public keys. If an IVT attribute specifies no public
......@@ -174,5 +177,7 @@ internal bool DeclaresTheObjectClass
return _lazyDeclaresTheObjectClass == ThreeState.True;
}
}
public AssemblyMetadata GetNonDisposableMetadata() => _owner.Copy();
}
}
......@@ -24,6 +24,12 @@ namespace Microsoft.CodeAnalysis
/// </summary>
internal sealed class PEModule : IDisposable
{
/// <summary>
/// We need to store reference to the module metadata to keep the metadata alive while
/// symbols have reference to PEModule.
/// </summary>
private readonly ModuleMetadata _owner;
// Either we have PEReader or we have pointer and size of the metadata blob:
private readonly PEReader _peReaderOpt;
private readonly IntPtr _metadataPointerOpt;
......@@ -76,13 +82,14 @@ internal sealed class PEModule : IDisposable
private static readonly AttributeValueExtractor<ObsoleteAttributeData> s_attributeObsoleteDataExtractor = CrackObsoleteAttributeData;
private static readonly AttributeValueExtractor<ObsoleteAttributeData> s_attributeDeprecatedDataExtractor = CrackDeprecatedAttributeData;
internal PEModule(PEReader peReader, IntPtr metadataOpt, int metadataSizeOpt, bool includeEmbeddedInteropTypes = false)
internal PEModule(ModuleMetadata owner, PEReader peReader, IntPtr metadataOpt, int metadataSizeOpt, bool includeEmbeddedInteropTypes = false)
{
// shall not throw
Debug.Assert((peReader == null) ^ (metadataOpt == IntPtr.Zero && metadataSizeOpt == 0));
Debug.Assert(metadataOpt == IntPtr.Zero || metadataSizeOpt > 0);
_owner = owner;
_peReaderOpt = peReader;
_metadataPointerOpt = metadataOpt;
_metadataSizeOpt = metadataSizeOpt;
......@@ -2966,5 +2973,7 @@ public unsafe override string GetString(byte* bytes, int byteCount)
return StringTable.AddSharedUTF8(bytes, byteCount);
}
}
public ModuleMetadata GetNonDisposableMetadata() => _owner.Copy();
}
}
......@@ -71,7 +71,7 @@ public bool IsDisposed
// creates a copy
private AssemblyMetadata(AssemblyMetadata other)
: base(isImageOwner: false)
: base(isImageOwner: false, id: other.Id)
{
this.CachedSymbols = other.CachedSymbols;
_lazyData = other._lazyData;
......@@ -81,14 +81,14 @@ private AssemblyMetadata(AssemblyMetadata other)
}
internal AssemblyMetadata(ImmutableArray<ModuleMetadata> modules)
: base(isImageOwner: true)
: base(isImageOwner: true, id: new MetadataId())
{
Debug.Assert(!modules.IsDefaultOrEmpty);
_initialModules = modules;
}
internal AssemblyMetadata(ModuleMetadata manifestModule, Func<string, ModuleMetadata> moduleFactory)
: base(isImageOwner: true)
: base(isImageOwner: true, id: new MetadataId())
{
Debug.Assert(manifestModule != null);
Debug.Assert(moduleFactory != null);
......
......@@ -5,6 +5,17 @@
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// An Id that can be used to identify a metadata instance. If two metadata instances
/// have the same id then they are guaranteed to have the same content. If two metadata
/// instances have different ids, then the contents may or may not be the same. As such,
/// the id is useful as a key in a cache when a client wants to share data for a metadata
/// reference as long as it has not changed.
/// </summary>
public sealed class MetadataId
{
}
/// <summary>
/// Represents immutable assembly or module CLI metadata.
/// </summary>
......@@ -12,9 +23,17 @@ public abstract class Metadata : IDisposable
{
internal readonly bool IsImageOwner;
internal Metadata(bool isImageOwner)
/// <summary>
/// The id for this metadata instance. If two metadata instances have the same id, then
/// they have the same content. If they have different ids they may or may not have the
/// same content.
/// </summary>
public MetadataId Id { get; }
internal Metadata(bool isImageOwner, MetadataId id)
{
this.IsImageOwner = isImageOwner;
this.Id = id;
}
/// <summary>
......
......@@ -22,20 +22,20 @@ public sealed partial class ModuleMetadata : Metadata
private readonly PEModule _module;
private ModuleMetadata(PEReader peReader)
: base(isImageOwner: true)
: base(isImageOwner: true, id: new MetadataId())
{
_module = new PEModule(peReader: peReader, metadataOpt: IntPtr.Zero, metadataSizeOpt: 0);
_module = new PEModule(this, peReader: peReader, metadataOpt: IntPtr.Zero, metadataSizeOpt: 0);
}
private ModuleMetadata(IntPtr metadata, int size, bool includeEmbeddedInteropTypes)
: base(isImageOwner: true)
: base(isImageOwner: true, id: new MetadataId())
{
_module = new PEModule(peReader: null, metadataOpt: metadata, metadataSizeOpt: size, includeEmbeddedInteropTypes: includeEmbeddedInteropTypes);
_module = new PEModule(this, peReader: null, metadataOpt: metadata, metadataSizeOpt: size, includeEmbeddedInteropTypes: includeEmbeddedInteropTypes);
}
// creates a copy
private ModuleMetadata(ModuleMetadata metadata)
: base(isImageOwner: false)
: base(isImageOwner: false, id: metadata.Id)
{
_module = metadata.Module;
}
......
......@@ -84,8 +84,12 @@ Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetryInfo.SyntaxNodeAct
Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetryInfo.SyntaxTreeActionsCount.get -> int
Microsoft.CodeAnalysis.Emit.DebugInformationFormat.Embedded = 3 -> Microsoft.CodeAnalysis.Emit.DebugInformationFormat
Microsoft.CodeAnalysis.Emit.DebugInformationFormat.PortablePdb = 2 -> Microsoft.CodeAnalysis.Emit.DebugInformationFormat
Microsoft.CodeAnalysis.IAssemblySymbol.GetMetadata() -> Microsoft.CodeAnalysis.AssemblyMetadata
Microsoft.CodeAnalysis.ICompilationUnitSyntax
Microsoft.CodeAnalysis.ICompilationUnitSyntax.EndOfFileToken.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.IModuleSymbol.GetMetadata() -> Microsoft.CodeAnalysis.ModuleMetadata
Microsoft.CodeAnalysis.Metadata.Id.get -> Microsoft.CodeAnalysis.MetadataId
Microsoft.CodeAnalysis.MetadataId
Microsoft.CodeAnalysis.MetadataReference.MetadataReference(Microsoft.CodeAnalysis.MetadataReferenceProperties properties) -> void
Microsoft.CodeAnalysis.ParseOptions.WithKind(Microsoft.CodeAnalysis.SourceCodeKind kind) -> Microsoft.CodeAnalysis.ParseOptions
Microsoft.CodeAnalysis.ScriptCompilationInfo
......
......@@ -71,5 +71,12 @@ public interface IAssemblySymbol : ISymbol
/// null is returned.
/// </summary>
INamedTypeSymbol ResolveForwardedType(string fullyQualifiedMetadataName);
/// <summary>
/// If this symbol represents a metadata assembly returns the underlying <see cref="AssemblyMetadata"/>.
///
/// Otherwise, this returns <code>null</code>.
/// </summary>
AssemblyMetadata GetMetadata();
}
}
......@@ -38,5 +38,12 @@ public interface IModuleSymbol : ISymbol
/// from ReferencedAssemblySymbols correspond to each other.
/// </summary>
ImmutableArray<IAssemblySymbol> ReferencedAssemblySymbols { get; }
/// <summary>
/// If this symbol represents a metadata module returns the underlying <see cref="ModuleMetadata"/>.
///
/// Otherwise, this returns <code>null</code>.
/// </summary>
ModuleMetadata GetMetadata();
}
}
......@@ -706,6 +706,10 @@ Friend Class MockModuleSymbol
Return Nothing
End Get
End Property
Public Overrides Function GetMetadata() As ModuleMetadata
Return Nothing
End Function
End Class
Friend Class MockAssemblySymbol
......@@ -802,4 +806,8 @@ Friend Class MockAssemblySymbol
Friend Overrides Function TryLookupForwardedMetadataTypeWithCycleDetection(ByRef emittedName As MetadataTypeName, visitedAssemblies As ConsList(Of AssemblySymbol), ignoreCase As Boolean) As NamedTypeSymbol
Return Nothing
End Function
Public Overrides Function GetMetadata() As AssemblyMetadata
Return Nothing
End Function
End Class
......@@ -78,6 +78,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Get
End Property
''' <summary>
''' If this symbol represents a metadata assembly returns the underlying <see cref="AssemblyMetadata"/>.
'''
''' Otherwise, this returns <code>nothing</code>.
''' </summary>
Public MustOverride Function GetMetadata() As AssemblyMetadata Implements IAssemblySymbol.GetMetadata
''' <summary>
''' Get the name of this assembly.
''' </summary>
......
......@@ -227,6 +227,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
Return Nothing
End Get
End Property
End Class
End Namespace
Public Overrides Function GetMetadata() As AssemblyMetadata
Return _assembly.GetNonDisposableMetadata()
End Function
End Class
End Namespace
\ No newline at end of file
......@@ -457,5 +457,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
Next
End Function
Public Overrides Function GetMetadata() As ModuleMetadata
Return _module.GetNonDisposableMetadata()
End Function
End Class
End Namespace
......@@ -143,6 +143,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Return False
End Get
End Property
Public Overrides Function GetMetadata() As AssemblyMetadata
Return Nothing
End Function
End Class
''' <summary>
......@@ -192,5 +196,4 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Function
End Class
End Namespace
End Namespace
\ No newline at end of file
......@@ -165,6 +165,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Return Nothing
End Get
End Property
Public Overrides Function GetMetadata() As ModuleMetadata
Return Nothing
End Function
End Class
Friend Class MissingModuleSymbolWithName
......@@ -200,5 +204,4 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Return other IsNot Nothing AndAlso m_Assembly.Equals(other.m_Assembly) AndAlso String.Equals(_name, other._name, StringComparison.OrdinalIgnoreCase)
End Function
End Class
End Namespace
End Namespace
\ No newline at end of file
......@@ -123,6 +123,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Get
End Property
''' <summary>
''' If this symbol represents a metadata module returns the underlying <see cref="ModuleMetadata"/>.
'''
''' Otherwise, this returns <code>nothing</code>.
''' </summary>
Public MustOverride Function GetMetadata() As ModuleMetadata Implements IModuleSymbol.GetMetadata
''' <summary>
''' Returns an array of assembly identities for assemblies referenced by this module.
''' Items at the same position from GetReferencedAssemblies and from GetReferencedAssemblySymbols
......
......@@ -246,5 +246,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting
Return Me.RetargetingTranslator.Retarget(underlying, RetargetOptions.RetargetPrimitiveTypesByName)
End Function
Public Overrides Function GetMetadata() As AssemblyMetadata
Return _underlyingAssembly.GetMetadata()
End Function
End Class
End Namespace
......@@ -273,5 +273,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting
Public Overrides Function GetDocumentationCommentXml(Optional preferredCulture As CultureInfo = Nothing, Optional expandIncludes As Boolean = False, Optional cancellationToken As CancellationToken = Nothing) As String
Return _underlyingModule.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken)
End Function
Public Overrides Function GetMetadata() As ModuleMetadata
Return _underlyingModule.GetMetadata()
End Function
End Class
End Namespace
......@@ -1683,5 +1683,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Return Nothing
End Function
Public Overrides Function GetMetadata() As AssemblyMetadata
Return Nothing
End Function
End Class
End Namespace
End Namespace
\ No newline at end of file
......@@ -1163,5 +1163,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Select
Next
End Sub
Public Overrides Function GetMetadata() As ModuleMetadata
Return Nothing
End Function
End Class
End Namespace
......@@ -249,8 +249,9 @@ private static ImmutableArray<ImmutableArray<string>> GetGroupedImportStrings(Co
compilation.Emit(exebits, pdbbits);
exebits.Position = 0;
using (var module = new PEModule(new PEReader(exebits, PEStreamOptions.LeaveOpen), metadataOpt: IntPtr.Zero, metadataSizeOpt: 0))
using (var metadata = ModuleMetadata.CreateFromStream(exebits, leaveOpen: true))
{
var module = metadata.Module;
var metadataReader = module.MetadataReader;
MethodDefinitionHandle methodHandle = metadataReader.MethodDefinitions.Single(mh => metadataReader.GetString(metadataReader.GetMethodDefinition(mh).Name) == methodName);
int methodToken = metadataReader.GetToken(methodHandle);
......
......@@ -376,8 +376,9 @@ internal static ImmutableArray<string> GetLocalNames(this ISymUnmanagedReader sy
throw new NotImplementedException();
}
using (var module = new PEModule(new PEReader(assembly), metadataOpt: IntPtr.Zero, metadataSizeOpt: 0))
using (var metadata = ModuleMetadata.CreateFromImage(assembly))
{
var module = metadata.Module;
var reader = module.MetadataReader;
var typeDef = reader.GetTypeDef(parts[0]);
var methodName = parts[1];
......
......@@ -97,10 +97,10 @@ internal int GetLocalSignatureToken(MethodDefinitionHandle methodHandle)
return 0;
}
using (var module = new PEModule(new PEReader(ImmutableArray.CreateRange(this.FullImage)), metadataOpt: IntPtr.Zero, metadataSizeOpt: 0))
using (var metadata = ModuleMetadata.CreateFromImage(this.FullImage))
{
var reader = module.MetadataReader;
var methodIL = module.GetMethodBodyOrThrow(methodHandle);
var reader = metadata.MetadataReader;
var methodIL = metadata.Module.GetMethodBodyOrThrow(methodHandle);
var localSignatureHandle = methodIL.LocalSignature;
return reader.GetToken(localSignatureHandle);
}
......
......@@ -124,7 +124,8 @@ End Namespace
compilation.Emit(exebits, pdbbits)
exebits.Position = 0
Using [module] As New PEModule(New PEReader(exebits, PEStreamOptions.LeaveOpen), metadataOpt:=Nothing, metadataSizeOpt:=0)
Using metadata = modulemetadata.CreateFromStream(exebits, leaveOpen:=True)
Dim [module] = metadata.module
Dim metadataReader = [module].MetadataReader
Dim methodHandle = metadataReader.MethodDefinitions.Single(Function(mh) metadataReader.GetString(metadataReader.GetMethodDefinition(mh).Name) = methodName)
Dim methodToken = metadataReader.GetToken(methodHandle)
......
......@@ -115,7 +115,7 @@ public override SymbolReference CreateReference<T>(SearchResult<T> searchResult)
protected override Task<IEnumerable<ISymbol>> FindDeclarationsAsync(string name, SymbolFilter filter, SearchQuery searchQuery)
{
return SymbolFinder.FindDeclarationsAsync(
_solution, _assembly, _metadataReference.FilePath, searchQuery, filter, cancellationToken);
_solution, _assembly, _metadataReference, searchQuery, filter, cancellationToken);
}
}
}
......
......@@ -196,7 +196,7 @@ public static Task<IEnumerable<ISymbol>> FindDeclarationsAsync(Project project,
else
{
await AddDeclarationsAsync(
project.Solution, assembly, GetMetadataReferenceFilePath(compilation.GetMetadataReference(assembly)),
project.Solution, assembly, compilation.GetMetadataReference(assembly) as PortableExecutableReference,
query, criteria, list, cancellationToken).ConfigureAwait(false);
}
}
......@@ -272,7 +272,7 @@ private static IEnumerable<ISymbol> TranslateNamespaces(List<ISymbol> symbols, C
}
internal static async Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
Solution solution, IAssemblySymbol assembly, string filePath, SearchQuery query, SymbolFilter filter, CancellationToken cancellationToken)
Solution solution, IAssemblySymbol assembly, PortableExecutableReference reference, SearchQuery query, SymbolFilter filter, CancellationToken cancellationToken)
{
if (query.Name != null && string.IsNullOrWhiteSpace(query.Name))
{
......@@ -280,18 +280,23 @@ private static IEnumerable<ISymbol> TranslateNamespaces(List<ISymbol> symbols, C
}
var result = new List<ISymbol>();
await AddDeclarationsAsync(solution, assembly, filePath, query, filter, result, cancellationToken).ConfigureAwait(false);
await AddDeclarationsAsync(solution, assembly, reference, query, filter, result, cancellationToken).ConfigureAwait(false);
return result;
}
private static async Task AddDeclarationsAsync(
Solution solution, IAssemblySymbol assembly, string filePath, SearchQuery query, SymbolFilter filter, List<ISymbol> list, CancellationToken cancellationToken)
Solution solution, IAssemblySymbol assembly, PortableExecutableReference referenceOpt, SearchQuery query, SymbolFilter filter, List<ISymbol> list, CancellationToken cancellationToken)
{
using (Logger.LogBlock(FunctionId.SymbolFinder_Assembly_AddDeclarationsAsync, cancellationToken))
{
var info = await SymbolTreeInfo.GetInfoForAssemblyAsync(solution, assembly, filePath, cancellationToken).ConfigureAwait(false);
list.AddRange(FilterByCriteria(Find(query, info, assembly, cancellationToken), filter));
if (referenceOpt != null)
{
var info = await SymbolTreeInfo.TryGetInfoForAssemblyAsync(solution, assembly, referenceOpt, cancellationToken).ConfigureAwait(false);
if (info != null)
{
list.AddRange(FilterByCriteria(Find(query, info, assembly, cancellationToken), filter));
}
}
}
}
......
......@@ -7,7 +7,6 @@
using System.Threading;
using System.Threading.Tasks;
using Roslyn.Utilities;
using static Roslyn.Utilities.PortableShim;
namespace Microsoft.CodeAnalysis.FindSymbols
{
......@@ -181,24 +180,49 @@ private int BinarySearch(string name)
#region Construction
private static readonly ConditionalWeakTable<IAssemblySymbol, SymbolTreeInfo> s_assemblyInfos = new ConditionalWeakTable<IAssemblySymbol, SymbolTreeInfo>();
// Cache the symbol tree infos for assembly symbols that share the same underlying metadata.
// Generating symbol trees for metadata can be expensive (in large metadata cases). And it's
// common for us to have many threads to want to search the same metadata simultaneously.
// As such, we want to only allow one thread to produce the tree for some piece of metadata
// at a time.
//
// AsyncLazy would normally be an ok choice here. However, in the case where all clients
// cancel their request, we don't want ot keep the AsyncLazy around. It may capture a lot
// of immutable state (like a Solution) that we don't want kept around indefinitely. So we
// only cache results (the symbol tree infos) if they successfully compute to completion.
private static readonly ConditionalWeakTable<MetadataId, SemaphoreSlim> s_metadataIdToGate = new ConditionalWeakTable<MetadataId, SemaphoreSlim>();
private static readonly ConditionalWeakTable<MetadataId, SymbolTreeInfo> s_metadataIdToInfo = new ConditionalWeakTable<MetadataId, SymbolTreeInfo>();
private static readonly ConditionalWeakTable<MetadataId, SemaphoreSlim>.CreateValueCallback s_metadataIdToGateCallback =
_ => new SemaphoreSlim(1);
/// <summary>
/// this gives you SymbolTreeInfo for a metadata
/// </summary>
public static async Task<SymbolTreeInfo> GetInfoForAssemblyAsync(Solution solution, IAssemblySymbol assembly, string filePath, CancellationToken cancellationToken)
public static async Task<SymbolTreeInfo> TryGetInfoForAssemblyAsync(Solution solution, IAssemblySymbol assembly, PortableExecutableReference reference, CancellationToken cancellationToken)
{
SymbolTreeInfo info;
if (s_assemblyInfos.TryGetValue(assembly, out info))
var metadata = assembly.GetMetadata();
if (metadata == null)
{
return info;
return null;
}
// IAssemblySymbol is immutable, even if we encounter a race, we might do same work twice but still will be correct.
// now, we can't use AsyncLazy here since constructing information requires a solution. if we ever get cancellation before
// finishing calculating, async lazy will hold onto solution graph until next call (if it ever gets called)
info = await LoadOrCreateAsync(solution, assembly, filePath, cancellationToken).ConfigureAwait(false);
return s_assemblyInfos.GetValue(assembly, _ => info);
// Find the lock associated with this piece of metadata. This way only one thread is
// computing a symbol tree info for a particular piece of metadata at a time.
var gate = s_metadataIdToGate.GetValue(metadata.Id, s_metadataIdToGateCallback);
using (await gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
cancellationToken.ThrowIfCancellationRequested();
SymbolTreeInfo info;
if (s_metadataIdToInfo.TryGetValue(metadata.Id, out info))
{
return info;
}
info = await LoadOrCreateAsync(solution, assembly, reference.FilePath, cancellationToken).ConfigureAwait(false);
return s_metadataIdToInfo.GetValue(metadata.Id, _ => info);
}
}
internal static SymbolTreeInfo Create(VersionStamp version, IAssemblySymbol assembly, CancellationToken cancellationToken)
......
......@@ -180,9 +180,9 @@ public void Test_SharedMetadataReferencesWithAliases()
Assert.NotNull(mdp2Sys3);
// all references to System.dll share the same metadata bytes
Assert.Same(mdp1Sys1, mdp1Sys2);
Assert.Same(mdp1Sys1, mdp2Sys1);
Assert.Same(mdp1Sys1, mdp2Sys3);
Assert.Same(mdp1Sys1.Id, mdp1Sys2.Id);
Assert.Same(mdp1Sys1.Id, mdp2Sys1.Id);
Assert.Same(mdp1Sys1.Id, mdp2Sys3.Id);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册