379 lines
12 KiB
C#
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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|