Files
2026-08-27 10:56:38 -06:00

379 lines
12 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.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<SynthesizedStaticField>
{
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<byte> Data, ushort Value)>
{
public static readonly DataAndUShortEqualityComparer Instance = new DataAndUShortEqualityComparer();
private DataAndUShortEqualityComparer()
{
}
public override bool Equals((ImmutableArray<byte> Data, ushort Value) x, (ImmutableArray<byte> Data, ushort Value) y)
{
if (x.Value == y.Value)
{
return ByteSequenceComparer.Equals(x.Data, y.Data);
}
return false;
}
public override int GetHashCode((ImmutableArray<byte> Data, ushort Value) obj)
{
return ByteSequenceComparer.GetHashCode(obj.Data);
}
}
private const string TypeNamePrefix = "<PrivateImplementationDetails>";
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<SynthesizedStaticField> _orderedSynthesizedFields;
private readonly ConcurrentDictionary<(ImmutableArray<byte> Data, ushort Alignment), MappedField> _mappedFields = new ConcurrentDictionary<(ImmutableArray<byte>, ushort), MappedField>(DataAndUShortEqualityComparer.Instance);
private readonly ConcurrentDictionary<(ImmutableArray<byte> Data, ushort ElementType), CachedArrayField> _cachedArrayFields = new ConcurrentDictionary<(ImmutableArray<byte>, ushort), CachedArrayField>(DataAndUShortEqualityComparer.Instance);
private ModuleVersionIdField? _mvidField;
private readonly ConcurrentDictionary<int, InstrumentationPayloadRootField> _instrumentationPayloadRootFields = new ConcurrentDictionary<int, InstrumentationPayloadRootField>();
private ImmutableArray<IMethodDefinition> _orderedSynthesizedMethods;
private readonly ConcurrentDictionary<string, IMethodDefinition> _synthesizedMethods = new ConcurrentDictionary<string, IMethodDefinition>();
private ImmutableArray<INamespaceTypeDefinition> _orderedTopLevelTypes;
private readonly ConcurrentDictionary<string, INamespaceTypeDefinition> _synthesizedTopLevelTypes = new ConcurrentDictionary<string, INamespaceTypeDefinition>();
private ImmutableArray<ITypeReference> _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) ? ("<PrivateImplementationDetails><" + MetadataHelpers.MangleForTypeNameIfNeeded(moduleName2) + ">") : "<PrivateImplementationDetails>");
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<SynthesizedStaticField> instance = ArrayBuilder<SynthesizedStaticField>.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<byte> data, IArrayTypeReference arrayType, EmitContext emitContext)
{
PrimitiveTypeCode typeCode = arrayType.GetElementType(emitContext).TypeCode;
return _cachedArrayFields.GetOrAdd((data, (ushort)typeCode), ((ImmutableArray<byte> Data, ushort ElementType) key) => new CachedArrayField($"{HashToHex(key.Data)}_A{key.ElementType}", this, arrayType));
}
internal IFieldReference CreateDataField(ImmutableArray<byte> 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<byte> 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<KeyValuePair<int, InstrumentationPayloadRootField>> GetInstrumentationPayloadRoots()
{
return _instrumentationPayloadRootFields.OrderBy<KeyValuePair<int, InstrumentationPayloadRootField>, int>((KeyValuePair<int, InstrumentationPayloadRootField> analysis) => analysis.Key);
}
internal bool TryAddSynthesizedMethod(IMethodDefinition method)
{
return _synthesizedMethods.TryAdd(method.Name, method);
}
public override IEnumerable<IFieldDefinition> GetFields(EmitContext context)
{
return _orderedSynthesizedFields;
}
public override IEnumerable<IMethodDefinition> GetMethods(EmitContext context)
{
return _orderedSynthesizedMethods;
}
public IEnumerable<IMethodDefinition> GetTopLevelTypeMethods(EmitContext context)
{
ImmutableArray<INamespaceTypeDefinition>.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<INamespaceTypeDefinition> GetAdditionalTopLevelTypes()
{
return _orderedTopLevelTypes;
}
public override IEnumerable<INestedTypeDefinition> GetNestedTypes(EmitContext context)
{
return _orderedProxyTypes.OfType<ExplicitSizeStruct>();
}
public override string ToString()
{
return Name;
}
public override ITypeReference GetBaseClass(EmitContext context)
{
return _systemObject;
}
public override IEnumerable<ICustomAttribute> GetAttributes(EmitContext context)
{
if (_compilerGeneratedAttribute != null)
{
return SpecializedCollections.SingletonEnumerable(_compilerGeneratedAttribute);
}
return SpecializedCollections.EmptyEnumerable<ICustomAttribute>();
}
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<byte> data)
{
ImmutableArray<byte> 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<byte> immutableArray, Span<char> destination)
{
int num = 0;
ReadOnlySpan<byte> 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);
}
}
}
}