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

140 lines
3.6 KiB
C#

using System.Collections.Concurrent;
using System.Collections.Immutable;
using Microsoft.Cci;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CodeGen;
internal class ArrayMethods
{
private enum ArrayMethodKind : byte
{
GET,
SET,
ADDRESS,
CTOR
}
private sealed class ArrayConstructor : ArrayMethod
{
public override string Name => ".ctor";
public ArrayConstructor(IArrayTypeReference arrayType)
: base(arrayType)
{
}
public override ITypeReference GetType(EmitContext context)
{
return context.Module.GetPlatformType(PlatformType.SystemVoid, context);
}
}
private sealed class ArrayGet : ArrayMethod
{
public override string Name => "Get";
public ArrayGet(IArrayTypeReference arrayType)
: base(arrayType)
{
}
public override ITypeReference GetType(EmitContext context)
{
return arrayType.GetElementType(context);
}
}
private sealed class ArrayAddress : ArrayMethod
{
public override bool ReturnValueIsByRef => true;
public override string Name => "Address";
public ArrayAddress(IArrayTypeReference arrayType)
: base(arrayType)
{
}
public override ITypeReference GetType(EmitContext context)
{
return arrayType.GetElementType(context);
}
}
private sealed class ArraySet : ArrayMethod
{
public override string Name => "Set";
public ArraySet(IArrayTypeReference arrayType)
: base(arrayType)
{
}
public override ITypeReference GetType(EmitContext context)
{
return context.Module.GetPlatformType(PlatformType.SystemVoid, context);
}
protected override ImmutableArray<ArrayMethodParameterInfo> MakeParameters()
{
int rank = arrayType.Rank;
ArrayBuilder<ArrayMethodParameterInfo> instance = ArrayBuilder<ArrayMethodParameterInfo>.GetInstance(rank + 1);
for (int i = 0; i < rank; i++)
{
instance.Add(ArrayMethodParameterInfo.GetIndexParameter((ushort)i));
}
instance.Add(new ArraySetValueParameterInfo((ushort)rank, arrayType));
return instance.ToImmutableAndFree();
}
}
private readonly ConcurrentDictionary<(byte methodKind, IReferenceOrISignature arrayType), ArrayMethod> _dict = new ConcurrentDictionary<(byte, IReferenceOrISignature), ArrayMethod>();
public ArrayMethod GetArrayConstructor(IArrayTypeReference arrayType)
{
return GetArrayMethod(arrayType, ArrayMethodKind.CTOR);
}
public ArrayMethod GetArrayGet(IArrayTypeReference arrayType)
{
return GetArrayMethod(arrayType, ArrayMethodKind.GET);
}
public ArrayMethod GetArraySet(IArrayTypeReference arrayType)
{
return GetArrayMethod(arrayType, ArrayMethodKind.SET);
}
public ArrayMethod GetArrayAddress(IArrayTypeReference arrayType)
{
return GetArrayMethod(arrayType, ArrayMethodKind.ADDRESS);
}
private ArrayMethod GetArrayMethod(IArrayTypeReference arrayType, ArrayMethodKind id)
{
(byte, IReferenceOrISignature) key = ((byte)id, new IReferenceOrISignature(arrayType));
ConcurrentDictionary<(byte, IReferenceOrISignature), ArrayMethod> dict = _dict;
if (!dict.TryGetValue(key, out var value))
{
value = MakeArrayMethod(arrayType, id);
return dict.GetOrAdd(key, value);
}
return value;
}
private static ArrayMethod MakeArrayMethod(IArrayTypeReference arrayType, ArrayMethodKind id)
{
return id switch
{
ArrayMethodKind.CTOR => new ArrayConstructor(arrayType),
ArrayMethodKind.GET => new ArrayGet(arrayType),
ArrayMethodKind.SET => new ArraySet(arrayType),
ArrayMethodKind.ADDRESS => new ArrayAddress(arrayType),
_ => throw ExceptionUtilities.UnexpectedValue(id),
};
}
}