using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; 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 PEModuleBuilder : CommonPEModuleBuilder, ITokenDeferral where TCompilation : Compilation where TSourceModuleSymbol : class, IModuleSymbolInternal where TAssemblySymbol : class, IAssemblySymbolInternal where TTypeSymbol : class, ITypeSymbolInternal where TNamedTypeSymbol : class, TTypeSymbol, INamedTypeSymbolInternal where TMethodSymbol : class, IMethodSymbolInternal where TSyntaxNode : SyntaxNode where TEmbeddedTypesManager : CommonEmbeddedTypesManager where TModuleCompilationState : ModuleCompilationState { private sealed class SynthesizedDefinitions { private ConcurrentQueue NestedTypes; public ConcurrentQueue Methods; public ConcurrentQueue Properties; public ConcurrentQueue Fields; internal IEnumerable OrderedNestedTypes => NestedTypes?.OrderBy((INestedTypeDefinition t) => t.Name, StringComparer.Ordinal); internal void AddNestedType(INestedTypeDefinition nestedType) { if (NestedTypes == null) { Interlocked.CompareExchange(ref NestedTypes, new ConcurrentQueue(), null); } NestedTypes.Enqueue(nestedType); } public ImmutableArray GetAllMembers() { ArrayBuilder instance = ArrayBuilder.GetInstance(); if (Fields != null) { foreach (IFieldDefinition field in Fields) { instance.Add(field.GetInternalSymbol()); } } if (Methods != null) { foreach (IMethodDefinition method in Methods) { instance.Add(method.GetInternalSymbol()); } } if (Properties != null) { foreach (IPropertyDefinition property in Properties) { instance.Add(property.GetInternalSymbol()); } } if (NestedTypes != null) { foreach (INestedTypeDefinition orderedNestedType in OrderedNestedTypes) { instance.Add(orderedNestedType.GetInternalSymbol()); } } return instance.ToImmutableAndFree(); } } internal readonly TSourceModuleSymbol SourceModule; internal readonly TCompilation Compilation; private PrivateImplementationDetails _lazyPrivateImplementationDetails; private ArrayMethods _lazyArrayMethods; private HashSet _namesOfTopLevelTypes; internal readonly TModuleCompilationState CompilationState; private readonly RootModuleType _rootModuleType; private readonly ConcurrentDictionary _synthesizedTypeMembers = new ConcurrentDictionary(Roslyn.Utilities.ReferenceEqualityComparer.Instance); private ConcurrentDictionary> _lazySynthesizedNamespaceMembers; public abstract TEmbeddedTypesManager EmbeddedTypesManagerOpt { get; } public RootModuleType RootModuleType => _rootModuleType; internal override IAssemblySymbolInternal CommonCorLibrary => CorLibrary; internal abstract TAssemblySymbol CorLibrary { get; } protected bool HaveDeterminedTopLevelTypes => _namesOfTopLevelTypes != null; internal sealed override IModuleSymbolInternal CommonSourceModule => SourceModule; internal sealed override Compilation CommonCompilation => Compilation; internal sealed override CommonModuleCompilationState CommonModuleCompilationState => CompilationState; internal sealed override CommonEmbeddedTypesManager CommonEmbeddedTypesManagerOpt => EmbeddedTypesManagerOpt; public ArrayMethods ArrayMethods { get { ArrayMethods arrayMethods = _lazyArrayMethods; if (arrayMethods == null) { arrayMethods = new ArrayMethods(); if (Interlocked.CompareExchange(ref _lazyArrayMethods, arrayMethods, null) != null) { arrayMethods = _lazyArrayMethods; } } return arrayMethods; } } protected PEModuleBuilder(TCompilation compilation, TSourceModuleSymbol sourceModule, ModulePropertiesForSerialization serializationProperties, IEnumerable manifestResources, OutputKind outputKind, EmitOptions emitOptions, TModuleCompilationState compilationState) : base(manifestResources, emitOptions, outputKind, serializationProperties, compilation) { Compilation = compilation; SourceModule = sourceModule; CompilationState = compilationState; _rootModuleType = new RootModuleType(this); } internal sealed override void CompilationFinished() { CompilationState.Freeze(); } internal abstract INamedTypeReference GetSpecialType(SpecialType specialType, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics); internal sealed override ITypeReference EncTranslateType(ITypeSymbolInternal type, DiagnosticBag diagnostics) { return EncTranslateLocalVariableType((TTypeSymbol)type, diagnostics); } internal virtual ITypeReference EncTranslateLocalVariableType(TTypeSymbol type, DiagnosticBag diagnostics) { return Translate(type, null, diagnostics); } protected bool ContainsTopLevelType(string fullEmittedName) { return _namesOfTopLevelTypes.Contains(fullEmittedName); } public override IEnumerable GetTopLevelTypeDefinitions(EmitContext context) { TypeReferenceIndexer typeReferenceIndexer = null; HashSet names = ((_namesOfTopLevelTypes != null) ? null : new HashSet()); if (EmbeddedTypesManagerOpt != null && !EmbeddedTypesManagerOpt.IsFrozen) { typeReferenceIndexer = new TypeReferenceIndexer(context); Dispatch(typeReferenceIndexer); } AddTopLevelType(names, RootModuleType); VisitTopLevelType(typeReferenceIndexer, RootModuleType); yield return RootModuleType; foreach (INamespaceTypeDefinition item in GetTopLevelTypeDefinitionsCore(context)) { AddTopLevelType(names, item); VisitTopLevelType(typeReferenceIndexer, item); yield return item; } if (EmbeddedTypesManagerOpt != null) { ImmutableArray.Enumerator enumerator2 = EmbeddedTypesManagerOpt.GetTypes(context.Diagnostics, names).GetEnumerator(); while (enumerator2.MoveNext()) { INamespaceTypeDefinition current2 = enumerator2.Current; AddTopLevelType(names, current2); yield return current2; } } if (names != null) { _namesOfTopLevelTypes = names; } static void AddTopLevelType(HashSet hashSet, INamespaceTypeDefinition type) { hashSet?.Add(MetadataHelpers.BuildQualifiedName(type.NamespaceName, MetadataWriter.GetMetadataName(type, 0))); } } public virtual ImmutableArray GetAdditionalTopLevelTypes() { return ImmutableArray.Empty; } public virtual ImmutableArray GetEmbeddedTypes(DiagnosticBag diagnostics) { return ImmutableArray.Empty; } internal abstract IAssemblyReference Translate(TAssemblySymbol symbol, DiagnosticBag diagnostics); internal abstract ITypeReference Translate(TTypeSymbol symbol, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics); internal abstract IMethodReference Translate(TMethodSymbol symbol, DiagnosticBag diagnostics, bool needDeclaration); internal sealed override IAssemblyReference Translate(IAssemblySymbolInternal symbol, DiagnosticBag diagnostics) { return Translate((TAssemblySymbol)symbol, diagnostics); } internal sealed override ITypeReference Translate(ITypeSymbolInternal symbol, SyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics) { return Translate((TTypeSymbol)symbol, (TSyntaxNode)syntaxNodeOpt, diagnostics); } internal sealed override IMethodReference Translate(IMethodSymbolInternal symbol, DiagnosticBag diagnostics, bool needDeclaration) { return Translate((TMethodSymbol)symbol, diagnostics, needDeclaration); } internal MetadataConstant CreateConstant(TTypeSymbol type, object value, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics) { return new MetadataConstant(Translate(type, syntaxNodeOpt, diagnostics), value); } private static void VisitTopLevelType(TypeReferenceIndexer noPiaIndexer, INamespaceTypeDefinition type) { noPiaIndexer?.Visit((ITypeDefinition)type); } internal IFieldReference GetModuleVersionId(ITypeReference mvidType, TSyntaxNode syntaxOpt, DiagnosticBag diagnostics) { PrivateImplementationDetails privateImplClass = GetPrivateImplClass(syntaxOpt, diagnostics); EnsurePrivateImplementationDetailsStaticConstructor(privateImplClass, syntaxOpt, diagnostics); return privateImplClass.GetModuleVersionId(mvidType); } internal IFieldReference GetInstrumentationPayloadRoot(int analysisKind, ITypeReference payloadType, TSyntaxNode syntaxOpt, DiagnosticBag diagnostics) { PrivateImplementationDetails privateImplClass = GetPrivateImplClass(syntaxOpt, diagnostics); EnsurePrivateImplementationDetailsStaticConstructor(privateImplClass, syntaxOpt, diagnostics); return privateImplClass.GetOrAddInstrumentationPayloadRoot(analysisKind, payloadType); } private void EnsurePrivateImplementationDetailsStaticConstructor(PrivateImplementationDetails details, TSyntaxNode syntaxOpt, DiagnosticBag diagnostics) { if (details.GetMethod(".cctor") == null) { details.TryAddSynthesizedMethod(CreatePrivateImplementationDetailsStaticConstructor(details, syntaxOpt, diagnostics)); } } protected abstract IMethodDefinition CreatePrivateImplementationDetailsStaticConstructor(PrivateImplementationDetails details, TSyntaxNode syntaxOpt, DiagnosticBag diagnostics); internal abstract IEnumerable GetSynthesizedNestedTypes(TNamedTypeSymbol container); public IEnumerable GetSynthesizedTypes(TNamedTypeSymbol container) { IEnumerable synthesizedNestedTypes = GetSynthesizedNestedTypes(container); IEnumerable enumerable = null; if (_synthesizedTypeMembers.TryGetValue(container, out var value)) { enumerable = value.OrderedNestedTypes; } if (synthesizedNestedTypes == null) { return enumerable; } if (enumerable == null) { return synthesizedNestedTypes; } return synthesizedNestedTypes.Concat(enumerable); } private SynthesizedDefinitions GetOrAddSynthesizedDefinitions(TNamedTypeSymbol container) { return _synthesizedTypeMembers.GetOrAdd(container, (TNamedTypeSymbol _) => new SynthesizedDefinitions()); } public void AddSynthesizedDefinition(TNamedTypeSymbol container, IMethodDefinition method) { SynthesizedDefinitions orAddSynthesizedDefinitions = GetOrAddSynthesizedDefinitions(container); if (orAddSynthesizedDefinitions.Methods == null) { Interlocked.CompareExchange(ref orAddSynthesizedDefinitions.Methods, new ConcurrentQueue(), null); } orAddSynthesizedDefinitions.Methods.Enqueue(method); } public void AddSynthesizedDefinition(TNamedTypeSymbol container, IPropertyDefinition property) { SynthesizedDefinitions orAddSynthesizedDefinitions = GetOrAddSynthesizedDefinitions(container); if (orAddSynthesizedDefinitions.Properties == null) { Interlocked.CompareExchange(ref orAddSynthesizedDefinitions.Properties, new ConcurrentQueue(), null); } orAddSynthesizedDefinitions.Properties.Enqueue(property); } public void AddSynthesizedDefinition(TNamedTypeSymbol container, IFieldDefinition field) { SynthesizedDefinitions orAddSynthesizedDefinitions = GetOrAddSynthesizedDefinitions(container); if (orAddSynthesizedDefinitions.Fields == null) { Interlocked.CompareExchange(ref orAddSynthesizedDefinitions.Fields, new ConcurrentQueue(), null); } orAddSynthesizedDefinitions.Fields.Enqueue(field); } public void AddSynthesizedDefinition(TNamedTypeSymbol container, INestedTypeDefinition nestedType) { GetOrAddSynthesizedDefinitions(container).AddNestedType(nestedType); } public void AddSynthesizedDefinition(INamespaceSymbolInternal container, INamespaceOrTypeSymbolInternal typeOrNamespace) { if (_lazySynthesizedNamespaceMembers == null) { Interlocked.CompareExchange(ref _lazySynthesizedNamespaceMembers, new ConcurrentDictionary>(), null); } _lazySynthesizedNamespaceMembers.GetOrAdd(container, (INamespaceSymbolInternal _) => new ConcurrentQueue()).Enqueue(typeOrNamespace); } public IEnumerable GetSynthesizedFields(TNamedTypeSymbol container) { if (!_synthesizedTypeMembers.TryGetValue(container, out var value)) { return null; } return value.Fields; } public IEnumerable GetSynthesizedProperties(TNamedTypeSymbol container) { if (!_synthesizedTypeMembers.TryGetValue(container, out var value)) { return null; } return value.Properties; } public IEnumerable GetSynthesizedMethods(TNamedTypeSymbol container) { if (!_synthesizedTypeMembers.TryGetValue(container, out var value)) { return null; } return value.Methods; } internal override ImmutableDictionary> GetAllSynthesizedMembers() { ImmutableDictionary>.Builder builder = ImmutableDictionary.CreateBuilder>(); foreach (KeyValuePair synthesizedTypeMember in _synthesizedTypeMembers) { builder.Add(synthesizedTypeMember.Key, synthesizedTypeMember.Value.GetAllMembers()); } ConcurrentDictionary> lazySynthesizedNamespaceMembers = _lazySynthesizedNamespaceMembers; if (lazySynthesizedNamespaceMembers != null) { foreach (KeyValuePair> item in lazySynthesizedNamespaceMembers) { builder.Add(item.Key, ((IEnumerable)item.Value).ToImmutableArray()); } } return builder.ToImmutable(); } IFieldReference ITokenDeferral.GetFieldForData(ImmutableArray data, ushort alignment, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { return GetPrivateImplClass((TSyntaxNode)syntaxNode, diagnostics).CreateDataField(data, alignment); } IFieldReference ITokenDeferral.GetArrayCachingFieldForData(ImmutableArray data, IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { PrivateImplementationDetails privateImplClass = GetPrivateImplClass((TSyntaxNode)syntaxNode, diagnostics); EmitContext emitContext = new EmitContext(this, syntaxNode, diagnostics, metadataOnly: false, includePrivateMembers: true); return privateImplClass.CreateArrayCachingField(data, arrayType, emitContext); } public abstract IMethodReference GetInitArrayHelper(); internal PrivateImplementationDetails GetPrivateImplClass(TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics) { PrivateImplementationDetails privateImplementationDetails = _lazyPrivateImplementationDetails; if (privateImplementationDetails == null) { privateImplementationDetails = new PrivateImplementationDetails(this, SourceModule.Name, Compilation.GetSubmissionSlotIndex(), GetSpecialType(SpecialType.System_Object, syntaxNodeOpt, diagnostics), GetSpecialType(SpecialType.System_ValueType, syntaxNodeOpt, diagnostics), GetSpecialType(SpecialType.System_Byte, syntaxNodeOpt, diagnostics), GetSpecialType(SpecialType.System_Int16, syntaxNodeOpt, diagnostics), GetSpecialType(SpecialType.System_Int32, syntaxNodeOpt, diagnostics), GetSpecialType(SpecialType.System_Int64, syntaxNodeOpt, diagnostics), SynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); if (Interlocked.CompareExchange(ref _lazyPrivateImplementationDetails, privateImplementationDetails, null) != null) { privateImplementationDetails = _lazyPrivateImplementationDetails; } } return privateImplementationDetails; } public PrivateImplementationDetails? FreezePrivateImplementationDetails() { _lazyPrivateImplementationDetails?.Freeze(); return _lazyPrivateImplementationDetails; } public override PrivateImplementationDetails? GetFrozenPrivateImplementationDetails() { return _lazyPrivateImplementationDetails; } public sealed override ITypeReference GetPlatformType(PlatformType platformType, EmitContext context) { if (platformType == PlatformType.SystemType) { throw ExceptionUtilities.UnexpectedValue(platformType); } return GetSpecialType((SpecialType)platformType, (TSyntaxNode)context.SyntaxNode, context.Diagnostics); } }