File: System\Reflection\TypeLoading\Types\RoModifiedFunctionPointerType.cs
Web Access
Project: src\src\libraries\System.Reflection.MetadataLoadContext\src\System.Reflection.MetadataLoadContext.csproj (System.Reflection.MetadataLoadContext)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.TypeLoading;
 
namespace System.Reflection
{
    /// <summary>
    /// A function pointer type that is modified and contains modified parameter and return types.
    /// </summary>
    internal sealed class RoModifiedFunctionPointerType : RoModifiedType
    {
        private const string CallingConventionTypePrefix = "System.Runtime.CompilerServices.CallConv";
 
        private readonly Type[] _callingConventions;
        private readonly RoModifiedType[] _parameterTypes;
        private readonly RoModifiedType _returnType;
 
        public RoModifiedFunctionPointerType(RoFunctionPointerType functionPointerType) : base(functionPointerType)
        {
            Debug.Assert(functionPointerType.IsFunctionPointer);
 
            Type[] parameterUnmodifiedTypes = functionPointerType._parameterTypes;
            int count = parameterUnmodifiedTypes.Length;
 
            RoModifiedType[] parameterTypes = new RoModifiedType[count];
            for (int i = 0; i < count; i++)
            {
                RoModifiedType parameter = Create((RoType)parameterUnmodifiedTypes[i]);
                parameterTypes[i] = parameter;
            }
 
            _parameterTypes = parameterTypes;
            _returnType = Create((RoType)functionPointerType._returnType);
 
            Type[] returnTypeOptionalModifiers = _returnType.GetOptionalCustomModifiers();
            _callingConventions = CreateCallingConventions(returnTypeOptionalModifiers, functionPointerType);
        }
 
        public override Type GetFunctionPointerReturnType() => _returnType;
        public override Type[] GetFunctionPointerParameterTypes() => Helpers.CloneArray(_parameterTypes);
        public override Type[] GetFunctionPointerCallingConventions() => Helpers.CloneArray(_callingConventions);
 
        private Type CDeclType => Loader.GetCoreType(CoreType.CallConvCdecl);
        private Type StdCallType => Loader.GetCoreType(CoreType.CallConvStdcall);
        private Type ThisCallType => Loader.GetCoreType(CoreType.CallConvThiscall);
        private Type FastCallType => Loader.GetCoreType(CoreType.CallConvFastcall);
 
        private Type[] CreateCallingConventions(Type[] returnTypeOptionalModifiers, RoFunctionPointerType functionPointerType)
        {
            List<Type> builder = new(returnTypeOptionalModifiers.Length + 1);
 
            // Normalize the calling conventions by manufacturing a type.
            switch (functionPointerType.CallKind)
            {
                case Metadata.SignatureCallingConvention.CDecl:
                    builder.Add(CDeclType);
                    break;
                case Metadata.SignatureCallingConvention.StdCall:
                    builder.Add(StdCallType);
                    break;
                case Metadata.SignatureCallingConvention.ThisCall:
                    builder.Add(ThisCallType);
                    break;
                case Metadata.SignatureCallingConvention.FastCall:
                    builder.Add(FastCallType);
                    break;
                case Metadata.SignatureCallingConvention.Unmanaged:
                    for (int i = 0; i < returnTypeOptionalModifiers.Length; i++)
                    {
                        Type type = returnTypeOptionalModifiers[i];
                        if (type.FullName!.StartsWith(CallingConventionTypePrefix, StringComparison.Ordinal))
                        {
                            builder.Add(type);
                        }
                    }
                    break;
            }
 
            return builder.Count == 0 ? EmptyTypes : builder.ToArray();
        }
    }
}