/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb
533 строки
25 KB
AlekseyTs
Avoid loading attributes for PE symbols for the purpose of getting AsyncMethodBuilderAttribute information. (#70625)
01 ноя 2023, 03:57
Не верифицирован
01 ноя 2023, 03:57
7eff5ed
Код
Авторство
О чём код?
' 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. Imports System.Collections.Concurrent Imports System.Collections.Immutable Imports System.Reflection Imports System.Reflection.Metadata Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE ''' <summary> ''' Represents a net-module imported from a PE. Can be a primary module of an assembly. ''' </summary> ''' <remarks></remarks> Friend NotInheritable Class PEModuleSymbol Inherits NonMissingModuleSymbol ''' <summary> ''' Owning AssemblySymbol. This can be a PEAssemblySymbol or a SourceAssemblySymbol. ''' </summary> ''' <remarks></remarks> Private ReadOnly _assemblySymbol As AssemblySymbol Private ReadOnly _ordinal As Integer ''' <summary> ''' A Module object providing metadata. ''' </summary> ''' <remarks></remarks> Private ReadOnly _module As PEModule ''' <summary> ''' Global namespace. ''' </summary> ''' <remarks></remarks> Private ReadOnly _globalNamespace As PENamespaceSymbol ''' <summary> ''' Cache the symbol for well-known type System.Type because we use it frequently ''' (for attributes). ''' </summary> Private _lazySystemTypeSymbol As NamedTypeSymbol ''' <summary> ''' The same value as ConcurrentDictionary.DEFAULT_CAPACITY ''' </summary> Private Const s_defaultTypeMapCapacity As Integer = 31 ''' <summary> ''' This is a map from TypeDef handle to the target <see cref="TypeSymbol"/>. ''' It is used by <see cref="MetadataDecoder"/> to speed up type reference resolution ''' for metadata coming from this module. The map is lazily populated ''' as we load types from the module. ''' </summary> Friend ReadOnly TypeHandleToTypeMap As New ConcurrentDictionary(Of TypeDefinitionHandle, TypeSymbol)(concurrencyLevel:=2, capacity:=s_defaultTypeMapCapacity) ''' <summary> ''' This is a map from TypeRef row id to the target <see cref="TypeSymbol"/>. ''' It is used by <see cref="MetadataDecoder"/> to speed-up type reference resolution ''' for metadata coming from this module. The map is lazily populated ''' by <see cref="MetadataDecoder"/> as we resolve TypeRefs from the module. ''' </summary> Friend ReadOnly TypeRefHandleToTypeMap As New ConcurrentDictionary(Of TypeReferenceHandle, TypeSymbol)(concurrencyLevel:=2, capacity:=s_defaultTypeMapCapacity) Friend ReadOnly MetadataLocation As ImmutableArray(Of MetadataLocation) = ImmutableArray.Create(Of MetadataLocation)(New MetadataLocation(Me)) Friend ReadOnly ImportOptions As MetadataImportOptions Private _lazyCustomAttributes As ImmutableArray(Of VisualBasicAttributeData) Private _lazyAssemblyAttributes As ImmutableArray(Of VisualBasicAttributeData) Private _lazyTypeNames As ICollection(Of String) Private _lazyNamespaceNames As ICollection(Of String) Private _lazyCachedCompilerFeatureRequiredDiagnosticInfo As DiagnosticInfo = ErrorFactory.EmptyDiagnosticInfo Private _lazyObsoleteAttributeData As ObsoleteAttributeData = ObsoleteAttributeData.Uninitialized Friend Sub New(assemblySymbol As PEAssemblySymbol, [module] As PEModule, importOptions As MetadataImportOptions, ordinal As Integer) Me.New(DirectCast(assemblySymbol, AssemblySymbol), [module], importOptions, ordinal) Debug.Assert(ordinal >= 0) End Sub Friend Sub New(assemblySymbol As SourceAssemblySymbol, [module] As PEModule, importOptions As MetadataImportOptions, ordinal As Integer) Me.New(DirectCast(assemblySymbol, AssemblySymbol), [module], importOptions, ordinal) Debug.Assert(ordinal >= 1) End Sub Friend Sub New(assemblySymbol As RetargetingAssemblySymbol, [module] As PEModule, importOptions As MetadataImportOptions, ordinal As Integer) Me.New(DirectCast(assemblySymbol, AssemblySymbol), [module], importOptions, ordinal) Debug.Assert(ordinal >= 1) End Sub Private Sub New(assemblySymbol As AssemblySymbol, [module] As PEModule, importOptions As MetadataImportOptions, ordinal As Integer) Debug.Assert(assemblySymbol IsNot Nothing) Debug.Assert([module] IsNot Nothing) _assemblySymbol = assemblySymbol _ordinal = ordinal _module = [module] _globalNamespace = New PEGlobalNamespaceSymbol(Me) Me.ImportOptions = importOptions End Sub Friend Overrides ReadOnly Property Ordinal As Integer Get Return _ordinal End Get End Property Friend Overrides ReadOnly Property Machine As System.Reflection.PortableExecutable.Machine Get Return _module.Machine End Get End Property Friend Overrides ReadOnly Property Bit32Required As Boolean Get Return _module.Bit32Required End Get End Property Friend ReadOnly Property [Module] As PEModule Get Return _module End Get End Property Public Overrides ReadOnly Property ContainingSymbol As Symbol Get Return _assemblySymbol End Get End Property Public Overloads Overrides Function GetAttributes() As ImmutableArray(Of VisualBasicAttributeData) If _lazyCustomAttributes.IsDefault Then 'TODO - Create a Module.Token to return token similar to Assembly.Token Me.LoadCustomAttributes(EntityHandle.ModuleDefinition, _lazyCustomAttributes) End If Return _lazyCustomAttributes End Function Friend Function GetAssemblyAttributes() As ImmutableArray(Of VisualBasicAttributeData) If _lazyAssemblyAttributes.IsDefault Then Dim moduleAssemblyAttributesBuilder As ArrayBuilder(Of VisualBasicAttributeData) = Nothing Dim corlibName As String = ContainingAssembly.CorLibrary.Name Dim assemblyMSCorLib As EntityHandle = [Module].GetAssemblyRef(corlibName) If Not assemblyMSCorLib.IsNil Then For Each qualifier In Cci.MetadataWriter.dummyAssemblyAttributeParentQualifier Dim typerefAssemblyAttributesGoHere As EntityHandle = [Module].GetTypeRef( assemblyMSCorLib, Cci.MetadataWriter.dummyAssemblyAttributeParentNamespace, Cci.MetadataWriter.dummyAssemblyAttributeParentName + qualifier) If Not typerefAssemblyAttributesGoHere.IsNil Then Try For Each customAttributeHandle In [Module].GetCustomAttributesOrThrow(typerefAssemblyAttributesGoHere) If moduleAssemblyAttributesBuilder Is Nothing Then moduleAssemblyAttributesBuilder = ArrayBuilder(Of VisualBasicAttributeData).GetInstance() End If moduleAssemblyAttributesBuilder.Add(New PEAttributeData(Me, customAttributeHandle)) Next Catch mrEx As BadImageFormatException End Try End If Next End If ImmutableInterlocked.InterlockedCompareExchange( _lazyAssemblyAttributes, If((moduleAssemblyAttributesBuilder IsNot Nothing), moduleAssemblyAttributesBuilder.ToImmutableAndFree(), ImmutableArray(Of VisualBasicAttributeData).Empty), Nothing) End If Return _lazyAssemblyAttributes End Function Friend Function GetCustomAttributesForToken(token As EntityHandle) As ImmutableArray(Of VisualBasicAttributeData) Return GetCustomAttributesForToken(token, Nothing, filterOut1:=Nothing) End Function Friend Function GetCustomAttributesForToken(token As EntityHandle, <Out()> ByRef filteredOutAttribute1 As CustomAttributeHandle, filterOut1 As AttributeDescription, <Out()> Optional ByRef filteredOutAttribute2 As CustomAttributeHandle = Nothing, Optional filterOut2 As AttributeDescription = Nothing) As ImmutableArray(Of VisualBasicAttributeData) Dim builder As ArrayBuilder(Of VisualBasicAttributeData) = Nothing filteredOutAttribute1 = Nothing filteredOutAttribute2 = Nothing Try For Each customAttributeHandle In Me.Module.GetCustomAttributesOrThrow(token) If builder Is Nothing Then builder = ArrayBuilder(Of VisualBasicAttributeData).GetInstance() End If If filterOut1.Signatures IsNot Nothing AndAlso [Module].GetTargetAttributeSignatureIndex( customAttributeHandle, filterOut1) <> -1 Then ' It is important to capture the last application of the attribute that we run into, ' it makes a difference for default and constant values. filteredOutAttribute1 = customAttributeHandle Continue For End If If filterOut2.Signatures IsNot Nothing AndAlso [Module].GetTargetAttributeSignatureIndex( customAttributeHandle, filterOut2) <> -1 Then ' It is important to capture the last application of the attribute that we run into, ' it makes a difference for default and constant values. filteredOutAttribute2 = customAttributeHandle Continue For End If builder.Add(New PEAttributeData(Me, customAttributeHandle)) Next Catch mrEx As BadImageFormatException End Try If builder IsNot Nothing Then Return builder.ToImmutableAndFree() End If Return ImmutableArray(Of VisualBasicAttributeData).Empty End Function Friend Sub LoadCustomAttributes(token As EntityHandle, ByRef lazyCustomAttributes As ImmutableArray(Of VisualBasicAttributeData)) Dim attributes As ImmutableArray(Of VisualBasicAttributeData) = GetCustomAttributesForToken(token) ImmutableInterlocked.InterlockedCompareExchange(Of VisualBasicAttributeData)( lazyCustomAttributes, attributes, Nothing) End Sub Public Overrides ReadOnly Property Name As String Get Return _module.Name End Get End Property Public Overrides ReadOnly Property GlobalNamespace As NamespaceSymbol Get Return _globalNamespace End Get End Property Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location) Get Return StaticCast(Of Location).From(Me.MetadataLocation) End Get End Property Public Overrides ReadOnly Property ContainingAssembly As AssemblySymbol Get Return _assemblySymbol End Get End Property Friend Sub OnNewTypeDeclarationsLoaded( typesDict As Dictionary(Of String, ImmutableArray(Of PENamedTypeSymbol)) ) Dim keepLookingForDeclaredCorTypes As Boolean = (_ordinal = 0 AndAlso _assemblySymbol.KeepLookingForDeclaredSpecialTypes) For Each types In typesDict.Values For Each t In types Dim added As Boolean added = TypeHandleToTypeMap.TryAdd(t.Handle, t) Debug.Assert(added) ' Register newly loaded COR types If (keepLookingForDeclaredCorTypes AndAlso t.SpecialType <> SpecialType.None) Then _assemblySymbol.RegisterDeclaredSpecialType(t) keepLookingForDeclaredCorTypes = _assemblySymbol.KeepLookingForDeclaredSpecialTypes End If Next Next End Sub Friend Overrides ReadOnly Property TypeNames As ICollection(Of String) Get If _lazyTypeNames Is Nothing Then Interlocked.CompareExchange(_lazyTypeNames, _module.TypeNames.AsCaseInsensitiveCollection(), Nothing) End If Return _lazyTypeNames End Get End Property Friend Overrides ReadOnly Property NamespaceNames As ICollection(Of String) Get If _lazyNamespaceNames Is Nothing Then Interlocked.CompareExchange(_lazyNamespaceNames, _module.NamespaceNames.AsCaseInsensitiveCollection(), Nothing) End If Return _lazyNamespaceNames End Get End Property Friend Overrides Function GetHash(algorithmId As AssemblyHashAlgorithm) As ImmutableArray(Of Byte) Return _module.GetHash(algorithmId) End Function Friend ReadOnly Property DocumentationProvider As DocumentationProvider Get Dim assembly = TryCast(ContainingAssembly, PEAssemblySymbol) If assembly IsNot Nothing Then Return assembly.DocumentationProvider Else Return DocumentationProvider.Default End If End Get End Property Friend ReadOnly Property SystemTypeSymbol As NamedTypeSymbol Get If _lazySystemTypeSymbol Is Nothing Then Interlocked.CompareExchange(_lazySystemTypeSymbol, GetWellKnownType(WellKnownType.System_Type), Nothing) Debug.Assert(_lazySystemTypeSymbol IsNot Nothing) End If Return _lazySystemTypeSymbol End Get End Property Public Function GetEventRegistrationTokenType() As NamedTypeSymbol Return GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationToken) End Function Private Function GetWellKnownType(type As WellKnownType) As NamedTypeSymbol Dim emittedName As MetadataTypeName = MetadataTypeName.FromFullName(type.GetMetadataName(), useCLSCompliantNameArityEncoding:=True) ' First, check this module Dim currentModuleResult As NamedTypeSymbol = Me.LookupTopLevelMetadataType(emittedName) Debug.Assert(If(Not currentModuleResult?.IsErrorType(), True)) If currentModuleResult IsNot Nothing Then Debug.Assert(IsAcceptableSystemTypeSymbol(currentModuleResult)) ' It doesn't matter if there's another System.Type in a referenced assembly - ' we prefer the one in the current module. Return currentModuleResult End If ' If we didn't find it in this module, check the referenced assemblies Dim referencedAssemblyResult As NamedTypeSymbol = Nothing For Each assembly As AssemblySymbol In Me.GetReferencedAssemblySymbols() Dim currResult As NamedTypeSymbol = assembly.LookupDeclaredOrForwardedTopLevelMetadataType(emittedName, visitedAssemblies:=Nothing) If IsAcceptableSystemTypeSymbol(currResult) Then If referencedAssemblyResult Is Nothing Then referencedAssemblyResult = currResult Else ' CONSIDER: setting result to null will result in a MissingMetadataTypeSymbol ' being returned. Do we want to differentiate between no result and ambiguous ' results? There doesn't seem to be an existing error code for "duplicate well- ' known type". If referencedAssemblyResult IsNot currResult Then referencedAssemblyResult = Nothing Exit For End If End If End If Next If referencedAssemblyResult IsNot Nothing Then Debug.Assert(IsAcceptableSystemTypeSymbol(referencedAssemblyResult)) Return referencedAssemblyResult End If Return New MissingMetadataTypeSymbol.TopLevel(Me, emittedName) End Function Private Shared Function IsAcceptableSystemTypeSymbol(candidate As NamedTypeSymbol) As Boolean Return candidate.Kind <> SymbolKind.ErrorType OrElse Not (TypeOf candidate Is MissingMetadataTypeSymbol) End Function Friend Overrides ReadOnly Property HasAssemblyCompilationRelaxationsAttribute As Boolean Get ' This API is called only for added modules. Assembly level attributes from added modules are ' copied to the resulting assembly and that is done by using VisualBasicAttributeData for them. ' Therefore, it is acceptable to implement this property by using the same VisualBasicAttributeData ' objects rather than trying to avoid creating them and going to metadata directly. Dim assemblyAttributes As ImmutableArray(Of VisualBasicAttributeData) = GetAssemblyAttributes() Return assemblyAttributes.IndexOfAttribute(AttributeDescription.CompilationRelaxationsAttribute) >= 0 End Get End Property Friend Overrides ReadOnly Property HasAssemblyRuntimeCompatibilityAttribute As Boolean Get ' This API is called only for added modules. Assembly level attributes from added modules are ' copied to the resulting assembly and that is done by using VisualBasicAttributeData for them. ' Therefore, it is acceptable to implement this property by using the same VisualBasicAttributeData ' objects rather than trying to avoid creating them and going to metadata directly. Dim assemblyAttributes As ImmutableArray(Of VisualBasicAttributeData) = GetAssemblyAttributes() Return assemblyAttributes.IndexOfAttribute(AttributeDescription.RuntimeCompatibilityAttribute) >= 0 End Get End Property Friend Overrides ReadOnly Property DefaultMarshallingCharSet As CharSet? Get Throw ExceptionUtilities.Unreachable End Get End Property ''' <remarks> ''' This is for perf, not for correctness. ''' </remarks> Friend Overrides ReadOnly Property DeclaringCompilation As VisualBasicCompilation Get Return Nothing End Get End Property Friend Overloads Function LookupTopLevelMetadataType(ByRef emittedName As MetadataTypeName, <Out> ByRef isNoPiaLocalType As Boolean) As NamedTypeSymbol Dim result As NamedTypeSymbol Dim scope = DirectCast(GlobalNamespace.LookupNestedNamespace(emittedName.NamespaceSegments), PENamespaceSymbol) If scope Is Nothing Then ' We failed to locate the namespace result = Nothing Else result = scope.LookupMetadataType(emittedName) If result Is Nothing Then result = scope.UnifyIfNoPiaLocalType(emittedName) If result IsNot Nothing Then isNoPiaLocalType = True Return result End If End If End If isNoPiaLocalType = False Return If(result, New MissingMetadataTypeSymbol.TopLevel(Me, emittedName)) End Function ''' <summary> ''' Returns a tuple of the assemblies this module forwards the given type to. ''' </summary> ''' <param name="fullName">Type to look up.</param> ''' <param name="ignoreCase">Pass true to look up fullName case-insensitively. WARNING: more expensive.</param> ''' <param name="matchedName">Returns the actual casing of the matching name.</param> ''' <returns>A tuple of the forwarded to assemblies.</returns> ''' <remarks> ''' The returned assemblies may also forward the type. ''' </remarks> Friend Function GetAssembliesForForwardedType(ByRef fullName As MetadataTypeName, ignoreCase As Boolean, <Out> ByRef matchedName As String) As (FirstSymbol As AssemblySymbol, SecondSymbol As AssemblySymbol) Dim indices = Me.Module.GetAssemblyRefsForForwardedType(fullName.FullName, ignoreCase, matchedName) If indices.FirstIndex < 0 Then Return (Nothing, Nothing) End If Dim firstSymbol = GetReferencedAssemblySymbol(indices.FirstIndex) If indices.SecondIndex < 0 Then Return (firstSymbol, Nothing) End If Dim secondSymbol = GetReferencedAssemblySymbol(indices.SecondIndex) Return (firstSymbol, secondSymbol) End Function Friend Iterator Function GetForwardedTypes() As IEnumerable(Of NamedTypeSymbol) For Each forwarder As KeyValuePair(Of String, (FirstIndex As Integer, SecondIndex As Integer)) In Me.Module.GetForwardedTypes() Dim name = MetadataTypeName.FromFullName(forwarder.Key) Debug.Assert(forwarder.Value.FirstIndex >= 0, "First index should never be negative") Dim firstSymbol = GetReferencedAssemblySymbol(forwarder.Value.FirstIndex) Debug.Assert(firstSymbol IsNot Nothing, "Invalid indexes (out of bound) are discarded during reading metadata in PEModule.EnsureForwardTypeToAssemblyMap()") If forwarder.Value.SecondIndex >= 0 Then Dim secondSymbol = GetReferencedAssemblySymbol(forwarder.Value.SecondIndex) Debug.Assert(secondSymbol IsNot Nothing, "Invalid indexes (out of bound) are discarded during reading metadata in PEModule.EnsureForwardTypeToAssemblyMap()") Yield ContainingAssembly.CreateMultipleForwardingErrorTypeSymbol(name, Me, firstSymbol, secondSymbol) Else Yield firstSymbol.LookupDeclaredOrForwardedTopLevelMetadataType(name, visitedAssemblies:=Nothing) End If Next End Function Public Overrides Function GetMetadata() As ModuleMetadata Return _module.GetNonDisposableMetadata() End Function Friend Function GetCompilerFeatureRequiredDiagnostic() As DiagnosticInfo If _lazyCachedCompilerFeatureRequiredDiagnosticInfo Is ErrorFactory.EmptyDiagnosticInfo Then Interlocked.CompareExchange( _lazyCachedCompilerFeatureRequiredDiagnosticInfo, DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, Me, EntityHandle.ModuleDefinition, CompilerFeatureRequiredFeatures.None, New MetadataDecoder(Me)), ErrorFactory.EmptyDiagnosticInfo) End If Return If(_lazyCachedCompilerFeatureRequiredDiagnosticInfo, TryCast(ContainingAssembly, PEAssemblySymbol)?.GetCompilerFeatureRequiredDiagnosticInfo()) End Function Public Overrides ReadOnly Property HasUnsupportedMetadata As Boolean Get Dim info = GetCompilerFeatureRequiredDiagnostic() If info IsNot Nothing Then Return info.Code = DirectCast(ERRID.ERR_UnsupportedCompilerFeature, Integer) OrElse MyBase.HasUnsupportedMetadata End If Return MyBase.HasUnsupportedMetadata End Get End Property Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData Get If _lazyObsoleteAttributeData Is ObsoleteAttributeData.Uninitialized Then Dim experimentalData = _module.TryDecodeExperimentalAttributeData(EntityHandle.ModuleDefinition, New MetadataDecoder(Me)) Interlocked.CompareExchange(_lazyObsoleteAttributeData, experimentalData, ObsoleteAttributeData.Uninitialized) End If Return _lazyObsoleteAttributeData End Get End Property End Class End Namespace