424 lines
17 KiB
C#
424 lines
17 KiB
C#
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<TCompilation, TSourceModuleSymbol, TAssemblySymbol, TTypeSymbol, TNamedTypeSymbol, TMethodSymbol, TSyntaxNode, TEmbeddedTypesManager, TModuleCompilationState> : 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<TNamedTypeSymbol, TMethodSymbol>
|
|
{
|
|
private sealed class SynthesizedDefinitions
|
|
{
|
|
private ConcurrentQueue<INestedTypeDefinition> NestedTypes;
|
|
|
|
public ConcurrentQueue<IMethodDefinition> Methods;
|
|
|
|
public ConcurrentQueue<IPropertyDefinition> Properties;
|
|
|
|
public ConcurrentQueue<IFieldDefinition> Fields;
|
|
|
|
internal IEnumerable<INestedTypeDefinition> OrderedNestedTypes => NestedTypes?.OrderBy<INestedTypeDefinition, string>((INestedTypeDefinition t) => t.Name, StringComparer.Ordinal);
|
|
|
|
internal void AddNestedType(INestedTypeDefinition nestedType)
|
|
{
|
|
if (NestedTypes == null)
|
|
{
|
|
Interlocked.CompareExchange(ref NestedTypes, new ConcurrentQueue<INestedTypeDefinition>(), null);
|
|
}
|
|
NestedTypes.Enqueue(nestedType);
|
|
}
|
|
|
|
public ImmutableArray<ISymbolInternal> GetAllMembers()
|
|
{
|
|
ArrayBuilder<ISymbolInternal> instance = ArrayBuilder<ISymbolInternal>.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<string> _namesOfTopLevelTypes;
|
|
|
|
internal readonly TModuleCompilationState CompilationState;
|
|
|
|
private readonly RootModuleType _rootModuleType;
|
|
|
|
private readonly ConcurrentDictionary<TNamedTypeSymbol, SynthesizedDefinitions> _synthesizedTypeMembers = new ConcurrentDictionary<TNamedTypeSymbol, SynthesizedDefinitions>(Roslyn.Utilities.ReferenceEqualityComparer.Instance);
|
|
|
|
private ConcurrentDictionary<INamespaceSymbolInternal, ConcurrentQueue<INamespaceOrTypeSymbolInternal>> _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<ResourceDescription> 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<INamespaceTypeDefinition> GetTopLevelTypeDefinitions(EmitContext context)
|
|
{
|
|
TypeReferenceIndexer typeReferenceIndexer = null;
|
|
HashSet<string> names = ((_namesOfTopLevelTypes != null) ? null : new HashSet<string>());
|
|
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<INamespaceTypeDefinition>.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<string> hashSet, INamespaceTypeDefinition type)
|
|
{
|
|
hashSet?.Add(MetadataHelpers.BuildQualifiedName(type.NamespaceName, MetadataWriter.GetMetadataName(type, 0)));
|
|
}
|
|
}
|
|
|
|
public virtual ImmutableArray<TNamedTypeSymbol> GetAdditionalTopLevelTypes()
|
|
{
|
|
return ImmutableArray<TNamedTypeSymbol>.Empty;
|
|
}
|
|
|
|
public virtual ImmutableArray<TNamedTypeSymbol> GetEmbeddedTypes(DiagnosticBag diagnostics)
|
|
{
|
|
return ImmutableArray<TNamedTypeSymbol>.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<INestedTypeDefinition> GetSynthesizedNestedTypes(TNamedTypeSymbol container);
|
|
|
|
public IEnumerable<INestedTypeDefinition> GetSynthesizedTypes(TNamedTypeSymbol container)
|
|
{
|
|
IEnumerable<INestedTypeDefinition> synthesizedNestedTypes = GetSynthesizedNestedTypes(container);
|
|
IEnumerable<INestedTypeDefinition> 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<IMethodDefinition>(), 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<IPropertyDefinition>(), 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<IFieldDefinition>(), 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<INamespaceSymbolInternal, ConcurrentQueue<INamespaceOrTypeSymbolInternal>>(), null);
|
|
}
|
|
_lazySynthesizedNamespaceMembers.GetOrAdd(container, (INamespaceSymbolInternal _) => new ConcurrentQueue<INamespaceOrTypeSymbolInternal>()).Enqueue(typeOrNamespace);
|
|
}
|
|
|
|
public IEnumerable<IFieldDefinition> GetSynthesizedFields(TNamedTypeSymbol container)
|
|
{
|
|
if (!_synthesizedTypeMembers.TryGetValue(container, out var value))
|
|
{
|
|
return null;
|
|
}
|
|
return value.Fields;
|
|
}
|
|
|
|
public IEnumerable<IPropertyDefinition> GetSynthesizedProperties(TNamedTypeSymbol container)
|
|
{
|
|
if (!_synthesizedTypeMembers.TryGetValue(container, out var value))
|
|
{
|
|
return null;
|
|
}
|
|
return value.Properties;
|
|
}
|
|
|
|
public IEnumerable<IMethodDefinition> GetSynthesizedMethods(TNamedTypeSymbol container)
|
|
{
|
|
if (!_synthesizedTypeMembers.TryGetValue(container, out var value))
|
|
{
|
|
return null;
|
|
}
|
|
return value.Methods;
|
|
}
|
|
|
|
internal override ImmutableDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>> GetAllSynthesizedMembers()
|
|
{
|
|
ImmutableDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>.Builder builder = ImmutableDictionary.CreateBuilder<ISymbolInternal, ImmutableArray<ISymbolInternal>>();
|
|
foreach (KeyValuePair<TNamedTypeSymbol, SynthesizedDefinitions> synthesizedTypeMember in _synthesizedTypeMembers)
|
|
{
|
|
builder.Add(synthesizedTypeMember.Key, synthesizedTypeMember.Value.GetAllMembers());
|
|
}
|
|
ConcurrentDictionary<INamespaceSymbolInternal, ConcurrentQueue<INamespaceOrTypeSymbolInternal>> lazySynthesizedNamespaceMembers = _lazySynthesizedNamespaceMembers;
|
|
if (lazySynthesizedNamespaceMembers != null)
|
|
{
|
|
foreach (KeyValuePair<INamespaceSymbolInternal, ConcurrentQueue<INamespaceOrTypeSymbolInternal>> item in lazySynthesizedNamespaceMembers)
|
|
{
|
|
builder.Add(item.Key, ((IEnumerable<ISymbolInternal>)item.Value).ToImmutableArray());
|
|
}
|
|
}
|
|
return builder.ToImmutable();
|
|
}
|
|
|
|
IFieldReference ITokenDeferral.GetFieldForData(ImmutableArray<byte> data, ushort alignment, SyntaxNode syntaxNode, DiagnosticBag diagnostics)
|
|
{
|
|
return GetPrivateImplClass((TSyntaxNode)syntaxNode, diagnostics).CreateDataField(data, alignment);
|
|
}
|
|
|
|
IFieldReference ITokenDeferral.GetArrayCachingFieldForData(ImmutableArray<byte> 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);
|
|
}
|
|
}
|