using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Security.Cryptography; using Microsoft.Cci; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit.NoPia; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Emit; internal abstract class CommonPEModuleBuilder : IUnit, IUnitReference, IReference, INamedEntity, IDefinition, IModuleReference { internal readonly DebugDocumentsBuilder DebugDocumentsBuilder; internal readonly IEnumerable ManifestResources; internal readonly ModulePropertiesForSerialization SerializationProperties; internal readonly OutputKind OutputKind; internal Stream? RawWin32Resources; internal IEnumerable? Win32Resources; internal ResourceSection? Win32ResourceSection; internal Stream? SourceLinkStreamOpt; internal IMethodReference? PEEntryPoint; internal IMethodReference? DebugEntryPoint; private readonly ConcurrentDictionary _methodBodyMap; private readonly TokenMap _referencesInILMap = new TokenMap(); private readonly ItemTokenMap _stringsInILMap = new ItemTokenMap(); private readonly ItemTokenMap _sourceDocumentsInILMap = new ItemTokenMap(); private ImmutableArray _lazyAssemblyReferenceAliases; private ImmutableArray _lazyManagedResources; private IEnumerable _embeddedTexts = SpecializedCollections.EmptyEnumerable(); internal CompilationTestData? TestData { get; private set; } internal EmitOptions EmitOptions { get; } internal DebugInformationFormat DebugInformationFormat => EmitOptions.DebugInformationFormat; internal HashAlgorithmName PdbChecksumAlgorithm => EmitOptions.PdbChecksumAlgorithm; public abstract SymbolChanges? EncSymbolChanges { get; } public abstract EmitBaseline? PreviousGeneration { get; } public bool IsEncDelta => PreviousGeneration != null; public int CurrentGenerationOrdinal { get { EmitBaseline? previousGeneration = PreviousGeneration; if (previousGeneration == null) { return 0; } return previousGeneration.Ordinal + 1; } } public abstract string Name { get; } internal abstract string ModuleName { get; } internal abstract Compilation CommonCompilation { get; } internal abstract IModuleSymbolInternal CommonSourceModule { get; } internal abstract IAssemblySymbolInternal CommonCorLibrary { get; } internal abstract CommonModuleCompilationState CommonModuleCompilationState { get; } internal abstract CommonEmbeddedTypesManager CommonEmbeddedTypesManagerOpt { get; } public abstract bool GenerateVisualBasicStylePdb { get; } public abstract IEnumerable LinkedAssembliesDebugInfo { get; } public abstract string DefaultNamespace { get; } public int DebugDocumentCount => DebugDocumentsBuilder.DebugDocumentCount; public abstract ISourceAssemblySymbolInternal SourceAssemblyOpt { get; } public int HintNumberOfMethodDefinitions => (int)((double)_methodBodyMap.Count * 1.5); public IEnumerable EmbeddedTexts { get { return _embeddedTexts; } set { _embeddedTexts = value; } } public CommonPEModuleBuilder(IEnumerable manifestResources, EmitOptions emitOptions, OutputKind outputKind, ModulePropertiesForSerialization serializationProperties, Compilation compilation) { ManifestResources = manifestResources; DebugDocumentsBuilder = new DebugDocumentsBuilder(compilation.Options.SourceReferenceResolver, compilation.IsCaseSensitive); OutputKind = outputKind; SerializationProperties = serializationProperties; _methodBodyMap = new ConcurrentDictionary(Roslyn.Utilities.ReferenceEqualityComparer.Instance); EmitOptions = emitOptions; } internal abstract IAssemblyReference Translate(IAssemblySymbolInternal symbol, DiagnosticBag diagnostics); internal abstract ITypeReference Translate(ITypeSymbolInternal symbol, SyntaxNode syntaxOpt, DiagnosticBag diagnostics); internal abstract IMethodReference Translate(IMethodSymbolInternal symbol, DiagnosticBag diagnostics, bool needDeclaration); internal abstract void CompilationFinished(); internal abstract ImmutableDictionary> GetAllSynthesizedMembers(); internal abstract ITypeReference EncTranslateType(ITypeSymbolInternal type, DiagnosticBag diagnostics); public abstract IEnumerable GetSourceAssemblyAttributes(bool isRefAssembly); public abstract IEnumerable GetSourceAssemblySecurityAttributes(); public abstract IEnumerable GetSourceModuleAttributes(); internal abstract ICustomAttribute SynthesizeAttribute(WellKnownMember attributeConstructor); public abstract ImmutableArray GetExportedTypes(DiagnosticBag diagnostics); public abstract ImmutableArray GetImports(); protected abstract IAssemblyReference GetCorLibraryReferenceToEmit(EmitContext context); protected abstract IEnumerable GetAssemblyReferencesFromAddedModules(DiagnosticBag diagnostics); protected abstract void AddEmbeddedResourcesFromAddedModules(ArrayBuilder builder, DiagnosticBag diagnostics); public abstract ITypeReference GetPlatformType(PlatformType platformType, EmitContext context); public abstract bool IsPlatformType(ITypeReference typeRef, PlatformType platformType); public abstract IEnumerable GetTopLevelTypeDefinitions(EmitContext context); public IEnumerable GetTopLevelTypeDefinitionsCore(EmitContext context) { foreach (INamespaceTypeDefinition anonymousTypeDefinition in GetAnonymousTypeDefinitions(context)) { yield return anonymousTypeDefinition; } foreach (INamespaceTypeDefinition additionalTopLevelTypeDefinition in GetAdditionalTopLevelTypeDefinitions(context)) { yield return additionalTopLevelTypeDefinition; } foreach (INamespaceTypeDefinition embeddedTypeDefinition in GetEmbeddedTypeDefinitions(context)) { yield return embeddedTypeDefinition; } foreach (INamespaceTypeDefinition topLevelSourceTypeDefinition in GetTopLevelSourceTypeDefinitions(context)) { yield return topLevelSourceTypeDefinition; } PrivateImplementationDetails privateImpl = GetFrozenPrivateImplementationDetails(); if (privateImpl == null) { yield break; } yield return privateImpl; foreach (INamespaceTypeDefinition additionalTopLevelType in privateImpl.GetAdditionalTopLevelTypes()) { yield return additionalTopLevelType; } } public abstract PrivateImplementationDetails? GetFrozenPrivateImplementationDetails(); public abstract IEnumerable GetAdditionalTopLevelTypeDefinitions(EmitContext context); public abstract IEnumerable GetAnonymousTypeDefinitions(EmitContext context); public abstract IEnumerable GetEmbeddedTypeDefinitions(EmitContext context); public abstract IEnumerable GetTopLevelSourceTypeDefinitions(EmitContext context); public abstract IEnumerable GetFiles(EmitContext context); public abstract MultiDictionary GetSymbolToLocationMap(); public abstract IEnumerable<(ITypeDefinition, ImmutableArray)> GetTypeToDebugDocumentMap(EmitContext context); public void Dispatch(MetadataVisitor visitor) { visitor.Visit(this); } IEnumerable IReference.GetAttributes(EmitContext context) { return SpecializedCollections.EmptyEnumerable(); } IDefinition IReference.AsDefinition(EmitContext context) { return this; } ISymbolInternal IReference.GetInternalSymbol() { return null; } internal IMethodBody GetMethodBody(IMethodSymbolInternal methodSymbol) { if (_methodBodyMap.TryGetValue(methodSymbol, out IMethodBody value)) { return value; } return null; } public void SetMethodBody(IMethodSymbolInternal methodSymbol, IMethodBody body) { _methodBodyMap.Add(methodSymbol, body); } internal void SetPEEntryPoint(IMethodSymbolInternal method, DiagnosticBag diagnostics) { PEEntryPoint = Translate(method, diagnostics, needDeclaration: true); } internal void SetDebugEntryPoint(IMethodSymbolInternal method, DiagnosticBag diagnostics) { DebugEntryPoint = Translate(method, diagnostics, needDeclaration: true); } private bool IsSourceDefinition(IMethodSymbolInternal method) { if (method.ContainingModule == CommonSourceModule) { return method.IsDefinition; } return false; } public IAssemblyReference GetCorLibrary(EmitContext context) { return Translate(CommonCorLibrary, context.Diagnostics); } public IAssemblyReference GetContainingAssembly(EmitContext context) { if (OutputKind != OutputKind.NetModule) { return (IAssemblyReference)this; } return null; } public IEnumerable GetStrings() { return _stringsInILMap.GetAllItems(); } public uint GetFakeSymbolTokenForIL(IReference symbol, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { bool referenceAdded; uint orAddTokenFor = _referencesInILMap.GetOrAddTokenFor(symbol, out referenceAdded); if (referenceAdded) { ReferenceDependencyWalker.VisitReference(symbol, new EmitContext(this, syntaxNode, diagnostics, metadataOnly: false, includePrivateMembers: true)); } return orAddTokenFor; } public uint GetFakeSymbolTokenForIL(ISignature symbol, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { bool referenceAdded; uint orAddTokenFor = _referencesInILMap.GetOrAddTokenFor(symbol, out referenceAdded); if (referenceAdded) { ReferenceDependencyWalker.VisitSignature(symbol, new EmitContext(this, syntaxNode, diagnostics, metadataOnly: false, includePrivateMembers: true)); } return orAddTokenFor; } public uint GetSourceDocumentIndexForIL(DebugSourceDocument document) { return _sourceDocumentsInILMap.GetOrAddTokenFor(document); } internal DebugSourceDocument GetSourceDocumentFromIndex(uint token) { return _sourceDocumentsInILMap.GetItem(token); } public object GetReferenceFromToken(uint token) { return _referencesInILMap.GetItem(token); } public uint GetFakeStringTokenForIL(string str) { return _stringsInILMap.GetOrAddTokenFor(str); } public string GetStringFromToken(uint token) { return _stringsInILMap.GetItem(token); } public ReadOnlySpan ReferencesInIL() { return _referencesInILMap.GetAllItems(); } public ImmutableArray GetAssemblyReferenceAliases(EmitContext context) { if (_lazyAssemblyReferenceAliases.IsDefault) { ImmutableInterlocked.InterlockedCompareExchange(ref _lazyAssemblyReferenceAliases, CalculateAssemblyReferenceAliases(context), default(ImmutableArray)); } return _lazyAssemblyReferenceAliases; } private ImmutableArray CalculateAssemblyReferenceAliases(EmitContext context) { ArrayBuilder instance = ArrayBuilder.GetInstance(); foreach (var referencedAssemblyAlias in CommonCompilation.GetBoundReferenceManager().GetReferencedAssemblyAliases()) { IAssemblySymbolInternal item = referencedAssemblyAlias.AssemblySymbol; ImmutableArray item2 = referencedAssemblyAlias.Aliases; for (int i = 0; i < item2.Length; i++) { string text = item2[i]; if (text != MetadataReferenceProperties.GlobalAlias && item2.IndexOf(text, 0, i) < 0) { instance.Add(new AssemblyReferenceAlias(text, Translate(item, context.Diagnostics))); } } } return instance.ToImmutableAndFree(); } public IEnumerable GetAssemblyReferences(EmitContext context) { IAssemblyReference corLibraryReferenceToEmit = GetCorLibraryReferenceToEmit(context); if (corLibraryReferenceToEmit != null) { yield return corLibraryReferenceToEmit; } if (OutputKind == OutputKind.NetModule) { yield break; } foreach (IAssemblyReference assemblyReferencesFromAddedModule in GetAssemblyReferencesFromAddedModules(context.Diagnostics)) { yield return assemblyReferencesFromAddedModule; } } public ImmutableArray GetResources(EmitContext context) { if (context.IsRefAssembly) { return ImmutableArray.Empty; } if (_lazyManagedResources.IsDefault) { ArrayBuilder instance = ArrayBuilder.GetInstance(); foreach (ResourceDescription manifestResource in ManifestResources) { instance.Add(manifestResource.ToManagedResource()); } if (OutputKind != OutputKind.NetModule) { AddEmbeddedResourcesFromAddedModules(instance, context.Diagnostics); } _lazyManagedResources = instance.ToImmutableAndFree(); } return _lazyManagedResources; } internal void SetTestData(CompilationTestData testData) { TestData = testData; testData.Module = this; } public int GetTypeDefinitionGeneration(INamedTypeDefinition typeDef) { if (PreviousGeneration != null) { SymbolChanges encSymbolChanges = EncSymbolChanges; if (encSymbolChanges.IsReplaced(typeDef)) { return CurrentGenerationOrdinal; } IDefinition definition = encSymbolChanges.DefinitionMap.MapDefinition(typeDef); if (definition != null && PreviousGeneration.GenerationOrdinals.TryGetValue(definition, out var value)) { return value; } } return 0; } }