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.Collections; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGen; internal sealed class PrivateImplementationDetails : DefaultTypeDef, INamespaceTypeDefinition, INamedTypeDefinition, ITypeDefinition, IDefinition, IReference, ITypeReference, INamedTypeReference, INamedEntity, INamespaceTypeReference { private sealed class FieldComparer : IComparer { public static readonly FieldComparer Instance = new FieldComparer(); private FieldComparer() { } public int Compare(SynthesizedStaticField? x, SynthesizedStaticField? y) { return x.Name.CompareTo(y.Name); } } private sealed class DataAndUShortEqualityComparer : EqualityComparer<(ImmutableArray Data, ushort Value)> { public static readonly DataAndUShortEqualityComparer Instance = new DataAndUShortEqualityComparer(); private DataAndUShortEqualityComparer() { } public override bool Equals((ImmutableArray Data, ushort Value) x, (ImmutableArray Data, ushort Value) y) { if (x.Value == y.Value) { return ByteSequenceComparer.Equals(x.Data, y.Data); } return false; } public override int GetHashCode((ImmutableArray Data, ushort Value) obj) { return ByteSequenceComparer.GetHashCode(obj.Data); } } private const string TypeNamePrefix = ""; internal const string SynthesizedStringHashFunctionName = "ComputeStringHash"; internal const string SynthesizedReadOnlySpanHashFunctionName = "ComputeReadOnlySpanHash"; internal const string SynthesizedSpanHashFunctionName = "ComputeSpanHash"; internal const string SynthesizedThrowSwitchExpressionExceptionFunctionName = "ThrowSwitchExpressionException"; internal const string SynthesizedThrowSwitchExpressionExceptionParameterlessFunctionName = "ThrowSwitchExpressionExceptionParameterless"; internal const string SynthesizedThrowInvalidOperationExceptionFunctionName = "ThrowInvalidOperationException"; internal const string SynthesizedInlineArrayAsSpanName = "InlineArrayAsSpan"; internal const string SynthesizedInlineArrayAsReadOnlySpanName = "InlineArrayAsReadOnlySpan"; internal const string SynthesizedInlineArrayElementRefName = "InlineArrayElementRef"; internal const string SynthesizedInlineArrayElementRefReadOnlyName = "InlineArrayElementRefReadOnly"; internal const string SynthesizedInlineArrayFirstElementRefName = "InlineArrayFirstElementRef"; internal const string SynthesizedInlineArrayFirstElementRefReadOnlyName = "InlineArrayFirstElementRefReadOnly"; private readonly CommonPEModuleBuilder _moduleBuilder; private readonly ITypeReference _systemObject; private readonly ITypeReference _systemValueType; private readonly ITypeReference _systemInt8Type; private readonly ITypeReference _systemInt16Type; private readonly ITypeReference _systemInt32Type; private readonly ITypeReference _systemInt64Type; private readonly ICustomAttribute _compilerGeneratedAttribute; private readonly string _name; private int _frozen; private ImmutableArray _orderedSynthesizedFields; private readonly ConcurrentDictionary<(ImmutableArray Data, ushort Alignment), MappedField> _mappedFields = new ConcurrentDictionary<(ImmutableArray, ushort), MappedField>(DataAndUShortEqualityComparer.Instance); private readonly ConcurrentDictionary<(ImmutableArray Data, ushort ElementType), CachedArrayField> _cachedArrayFields = new ConcurrentDictionary<(ImmutableArray, ushort), CachedArrayField>(DataAndUShortEqualityComparer.Instance); private ModuleVersionIdField? _mvidField; private readonly ConcurrentDictionary _instrumentationPayloadRootFields = new ConcurrentDictionary(); private ImmutableArray _orderedSynthesizedMethods; private readonly ConcurrentDictionary _synthesizedMethods = new ConcurrentDictionary(); private ImmutableArray _orderedTopLevelTypes; private readonly ConcurrentDictionary _synthesizedTopLevelTypes = new ConcurrentDictionary(); private ImmutableArray _orderedProxyTypes; private readonly ConcurrentDictionary<(uint Size, ushort Alignment), ITypeReference> _proxyTypes = new ConcurrentDictionary<(uint, ushort), ITypeReference>(); internal bool IsFrozen => _frozen != 0; public override INamespaceTypeReference AsNamespaceTypeReference => this; public string Name => _name; public bool IsPublic => false; public string NamespaceName => string.Empty; internal PrivateImplementationDetails(CommonPEModuleBuilder moduleBuilder, string moduleName, int submissionSlotIndex, ITypeReference systemObject, ITypeReference systemValueType, ITypeReference systemInt8Type, ITypeReference systemInt16Type, ITypeReference systemInt32Type, ITypeReference systemInt64Type, ICustomAttribute compilerGeneratedAttribute) { CommonPEModuleBuilder moduleBuilder2 = moduleBuilder; string moduleName2 = moduleName; int submissionSlotIndex2 = submissionSlotIndex; base._002Ector(); _moduleBuilder = moduleBuilder2; _systemObject = systemObject; _systemValueType = systemValueType; _systemInt8Type = systemInt8Type; _systemInt16Type = systemInt16Type; _systemInt32Type = systemInt32Type; _systemInt64Type = systemInt64Type; _compilerGeneratedAttribute = compilerGeneratedAttribute; _name = getClassName(); string getClassName() { string text = ((moduleBuilder2.OutputKind == OutputKind.NetModule) ? ("<" + MetadataHelpers.MangleForTypeNameIfNeeded(moduleName2) + ">") : ""); if (submissionSlotIndex2 >= 0) { text += submissionSlotIndex2; } if (moduleBuilder2.CurrentGenerationOrdinal > 0) { text = text + "#" + moduleBuilder2.CurrentGenerationOrdinal; } return text; } } internal void Freeze() { if (Interlocked.Exchange(ref _frozen, 1) != 0) { throw new InvalidOperationException(); } ArrayBuilder instance = ArrayBuilder.GetInstance(_mappedFields.Count + _cachedArrayFields.Count + ((_mvidField != null) ? 1 : 0)); instance.AddRange(_mappedFields.Values); instance.AddRange(_cachedArrayFields.Values); if (_mvidField != null) { instance.Add(_mvidField); } instance.AddRange(_instrumentationPayloadRootFields.Values); instance.Sort(FieldComparer.Instance); _orderedSynthesizedFields = instance.ToImmutableAndFree(); _orderedSynthesizedMethods = (from kvp in _synthesizedMethods orderby kvp.Key select kvp.Value).AsImmutable(); _orderedTopLevelTypes = (from kvp in _synthesizedTopLevelTypes orderby kvp.Key select kvp.Value).AsImmutable(); _orderedProxyTypes = (from kvp in _proxyTypes orderby kvp.Key.Size, kvp.Key.Alignment select kvp.Value).AsImmutable(); } internal IFieldReference CreateArrayCachingField(ImmutableArray data, IArrayTypeReference arrayType, EmitContext emitContext) { PrimitiveTypeCode typeCode = arrayType.GetElementType(emitContext).TypeCode; return _cachedArrayFields.GetOrAdd((data, (ushort)typeCode), ((ImmutableArray Data, ushort ElementType) key) => new CachedArrayField($"{HashToHex(key.Data)}_A{key.ElementType}", this, arrayType)); } internal IFieldReference CreateDataField(ImmutableArray data, ushort alignment) { ITypeReference type = _proxyTypes.GetOrAdd(((uint)data.Length, alignment), delegate((uint Size, ushort Alignment) key) { if (key.Alignment == 1) { switch (key.Size) { case 1u: if (_systemInt8Type != null) { return _systemInt8Type; } break; case 2u: if (_systemInt16Type != null) { return _systemInt16Type; } break; case 4u: if (_systemInt32Type != null) { return _systemInt32Type; } break; case 8u: if (_systemInt64Type != null) { return _systemInt64Type; } break; } } return new ExplicitSizeStruct(key.Size, key.Alignment, this, _systemValueType); }); return _mappedFields.GetOrAdd((data, alignment), delegate((ImmutableArray Data, ushort Alignment) key) { string text = HashToHex(key.Data); return new MappedField(alignment switch { 2 => text + "2", 4 => text + "4", 8 => text + "8", _ => text, }, this, type, key.Data); }); } internal IFieldReference GetModuleVersionId(ITypeReference mvidType) { if (_mvidField == null) { Interlocked.CompareExchange(ref _mvidField, new ModuleVersionIdField(this, mvidType), null); } return _mvidField; } internal IFieldReference GetOrAddInstrumentationPayloadRoot(int analysisKind, ITypeReference payloadRootType) { if (!_instrumentationPayloadRootFields.TryGetValue(analysisKind, out InstrumentationPayloadRootField value)) { return _instrumentationPayloadRootFields.GetOrAdd(analysisKind, (int kind) => new InstrumentationPayloadRootField(this, kind, payloadRootType)); } return value; } internal IOrderedEnumerable> GetInstrumentationPayloadRoots() { return _instrumentationPayloadRootFields.OrderBy, int>((KeyValuePair analysis) => analysis.Key); } internal bool TryAddSynthesizedMethod(IMethodDefinition method) { return _synthesizedMethods.TryAdd(method.Name, method); } public override IEnumerable GetFields(EmitContext context) { return _orderedSynthesizedFields; } public override IEnumerable GetMethods(EmitContext context) { return _orderedSynthesizedMethods; } public IEnumerable GetTopLevelTypeMethods(EmitContext context) { ImmutableArray.Enumerator enumerator = _orderedTopLevelTypes.GetEnumerator(); while (enumerator.MoveNext()) { INamespaceTypeDefinition current = enumerator.Current; foreach (IMethodDefinition method in current.GetMethods(context)) { yield return method; } } } internal IMethodDefinition? GetMethod(string name) { _synthesizedMethods.TryGetValue(name, out IMethodDefinition value); return value; } internal bool TryAddSynthesizedType(INamespaceTypeDefinition type) { return _synthesizedTopLevelTypes.TryAdd(type.Name, type); } internal INamespaceTypeDefinition? GetSynthesizedType(string name) { _synthesizedTopLevelTypes.TryGetValue(name, out INamespaceTypeDefinition value); return value; } internal IEnumerable GetAdditionalTopLevelTypes() { return _orderedTopLevelTypes; } public override IEnumerable GetNestedTypes(EmitContext context) { return _orderedProxyTypes.OfType(); } public override string ToString() { return Name; } public override ITypeReference GetBaseClass(EmitContext context) { return _systemObject; } public override IEnumerable GetAttributes(EmitContext context) { if (_compilerGeneratedAttribute != null) { return SpecializedCollections.SingletonEnumerable(_compilerGeneratedAttribute); } return SpecializedCollections.EmptyEnumerable(); } public override void Dispatch(MetadataVisitor visitor) { visitor.Visit(this); } public override INamespaceTypeDefinition AsNamespaceTypeDefinition(EmitContext context) { return this; } public IUnitReference GetUnit(EmitContext context) { return _moduleBuilder; } private static string HashToHex(ImmutableArray data) { ImmutableArray source = CryptographicHashProvider.ComputeSourceHash(data); char[] array = new char[source.Length * 2]; toHex(source, array); return new string(array); static char hexchar(int x) { return (char)((x <= 9) ? (x + 48) : (x + 55)); } static void toHex(ImmutableArray immutableArray, Span destination) { int num = 0; ReadOnlySpan readOnlySpan = immutableArray.AsSpan(); for (int i = 0; i < readOnlySpan.Length; i++) { byte b = readOnlySpan[i]; destination[num++] = hexchar(b >> 4); destination[num++] = hexchar(b & 0xF); } } } }