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