internal static MarshallerKind GetMarshallerKind()

in src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs [215:671]


        internal static MarshallerKind GetMarshallerKind(
            TypeDesc type,
            int? parameterIndex,
            EmbeddedSignatureData[] customModifierData,
            MarshalAsDescriptor marshalAs,
            bool isReturn,
            bool isAnsi,
            MarshallerType marshallerType,
            out MarshallerKind elementMarshallerKind)
        {
            elementMarshallerKind = MarshallerKind.Invalid;

            TypeSystemContext context = type.Context;
            NativeTypeKind nativeType = NativeTypeKind.Default;
            bool isField = marshallerType == MarshallerType.Field;

            if (marshalAs != null)
                nativeType = marshalAs.Type;

            bool isByRef = type.IsByRef;
            if (isByRef)
            {
                type = type.GetParameterType();

                if (type.IsValueType && !type.IsPrimitive && !type.IsEnum && !isField
                    && HasCopyConstructorCustomModifier(parameterIndex, customModifierData))
                {
                    return MarshallerKind.BlittableValueClassWithCopyCtor;
                }

                if (isReturn)
                {
                    // Allow ref returning blittable structs for IJW
                    if (type.IsValueType &&
                        (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default) &&
                        MarshalUtils.IsBlittableType(type))
                    {
                        return MarshallerKind.BlittableValueClassByRefReturn;
                    }
                    return MarshallerKind.Invalid;
                }
            }

            if (nativeType == NativeTypeKind.CustomMarshaler)
            {
                if (isField)
                    return MarshallerKind.FailedTypeLoad;
                else
                    return MarshallerKind.CustomMarshaler;
            }

            //
            // Determine MarshalerKind
            //
            if (type.IsPrimitive)
            {
                switch (type.Category)
                {
                    case TypeFlags.Void:
                        return MarshallerKind.VoidReturn;

                    case TypeFlags.Boolean:
                        switch (nativeType)
                        {
                            case NativeTypeKind.Default:
                            case NativeTypeKind.Boolean:
                                return MarshallerKind.Bool;

                            case NativeTypeKind.U1:
                            case NativeTypeKind.I1:
                                return MarshallerKind.CBool;

                            case NativeTypeKind.VariantBool:
                                if (context.Target.IsWindows)
                                    return MarshallerKind.VariantBool;
                                else
                                    return MarshallerKind.Invalid;

                            default:
                                return MarshallerKind.Invalid;
                        }

                    case TypeFlags.Char:
                        switch (nativeType)
                        {
                            case NativeTypeKind.I1:
                            case NativeTypeKind.U1:
                                return MarshallerKind.AnsiChar;

                            case NativeTypeKind.I2:
                            case NativeTypeKind.U2:
                                return MarshallerKind.UnicodeChar;

                            case NativeTypeKind.Default:
                                if (isAnsi)
                                    return MarshallerKind.AnsiChar;
                                else
                                    return MarshallerKind.UnicodeChar;
                            default:
                                return MarshallerKind.Invalid;
                        }

                    case TypeFlags.SByte:
                    case TypeFlags.Byte:
                        if (nativeType == NativeTypeKind.I1 || nativeType == NativeTypeKind.U1 || nativeType == NativeTypeKind.Default)
                            return MarshallerKind.BlittableValue;
                        else
                            return MarshallerKind.Invalid;

                    case TypeFlags.Int16:
                    case TypeFlags.UInt16:
                        if (nativeType == NativeTypeKind.I2 || nativeType == NativeTypeKind.U2 || nativeType == NativeTypeKind.Default)
                            return MarshallerKind.BlittableValue;
                        else
                            return MarshallerKind.Invalid;

                    case TypeFlags.Int32:
                    case TypeFlags.UInt32:
                        if (nativeType == NativeTypeKind.I4 || nativeType == NativeTypeKind.U4 || nativeType == NativeTypeKind.Default)
                            return MarshallerKind.BlittableValue;
                        else
                            return MarshallerKind.Invalid;

                    case TypeFlags.Int64:
                    case TypeFlags.UInt64:
                        if (nativeType == NativeTypeKind.I8 || nativeType == NativeTypeKind.U8 || nativeType == NativeTypeKind.Default)
                            return MarshallerKind.BlittableValue;
                        else
                            return MarshallerKind.Invalid;

                    case TypeFlags.IntPtr:
                    case TypeFlags.UIntPtr:
                        if (nativeType == NativeTypeKind.SysInt || nativeType == NativeTypeKind.SysUInt || nativeType == NativeTypeKind.Default)
                            return MarshallerKind.BlittableValue;
                        else
                            return MarshallerKind.Invalid;

                    case TypeFlags.Single:
                        if (nativeType == NativeTypeKind.R4 || nativeType == NativeTypeKind.Default)
                            return MarshallerKind.BlittableValue;
                        else
                            return MarshallerKind.Invalid;

                    case TypeFlags.Double:
                        if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Default)
                            return MarshallerKind.BlittableValue;
                        else
                            return MarshallerKind.Invalid;

                    default:
                        return MarshallerKind.Invalid;
                }
            }
            else if (type.IsValueType)
            {
                if (type.IsEnum)
                    return MarshallerKind.Enum;

                if (InteropTypes.IsSystemDateTime(context, type))
                {
                    if (nativeType == NativeTypeKind.Default ||
                        nativeType == NativeTypeKind.Struct)
                        return MarshallerKind.OleDateTime;
                    else
                        return MarshallerKind.Invalid;
                }
                else if (InteropTypes.IsHandleRef(context, type))
                {
                    if (nativeType == NativeTypeKind.Default)
                        return MarshallerKind.HandleRef;
                    else
                        return MarshallerKind.Invalid;
                }
                else if (InteropTypes.IsSystemDecimal(context, type))
                {
                    if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default)
                        return MarshallerKind.Decimal;
                    else if (nativeType == NativeTypeKind.LPStruct && !isField)
                        return MarshallerKind.BlittableStructPtr;
                    else if (nativeType == NativeTypeKind.Currency)
                        return MarshallerKind.OleCurrency;
                    else
                        return MarshallerKind.Invalid;
                }
                else if (InteropTypes.IsSystemGuid(context, type))
                {
                    if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default)
                        return MarshallerKind.BlittableStruct;
                    else if (nativeType == NativeTypeKind.LPStruct && !isField)
                        return MarshallerKind.BlittableStructPtr;
                    else
                        return MarshallerKind.Invalid;
                }
                else if (InteropTypes.IsSystemArgIterator(context, type))
                {
                    // Don't want to fall through to the blittable/haslayout case
                    return MarshallerKind.Invalid;
                }

                if (!IsValidForGenericMarshalling(type, isField))
                {
                    // Generic types cannot be marshalled.
                    return MarshallerKind.Invalid;
                }

                if (!isField && ((DefType)type).IsInt128OrHasInt128Fields && !isByRef)
                {
                    // Int128 types or structs that contain them cannot be passed by value
                    return MarshallerKind.Invalid;
                }

                if (!isField && ((DefType)type).IsVectorTOrHasVectorTFields)
                {
                    // Vector<T> types or structs that contain them cannot be passed by value
                    return MarshallerKind.Invalid;
                }

                if (MarshalUtils.IsBlittableType(type))
                {
                    if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct)
                        return MarshallerKind.Invalid;

                    return MarshallerKind.BlittableStruct;
                }
                else if (((MetadataType)type).HasLayout())
                {
                    if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct)
                        return MarshallerKind.Invalid;

                    return MarshallerKind.Struct;
                }
                else
                {
                    return MarshallerKind.Invalid;
                }
            }
            else if (type.IsSzArray)
            {
                if (nativeType == NativeTypeKind.Default)
                    nativeType = NativeTypeKind.Array;

                switch (nativeType)
                {
                    case NativeTypeKind.Array:
                        {
                            if (isField)
                                return MarshallerKind.FailedTypeLoad;

                            var arrayType = (ArrayType)type;

                            elementMarshallerKind = GetArrayElementMarshallerKind(
                                arrayType,
                                marshalAs,
                                isAnsi);

                            // If element is invalid type, the array itself is invalid
                            if (elementMarshallerKind == MarshallerKind.Invalid)
                                return MarshallerKind.Invalid;

                            if (elementMarshallerKind == MarshallerKind.AnsiChar)
                                return MarshallerKind.AnsiCharArray;
                            else if (elementMarshallerKind == MarshallerKind.UnicodeChar    // Arrays of unicode char should be marshalled as blittable arrays
                                || elementMarshallerKind == MarshallerKind.Enum
                                || elementMarshallerKind == MarshallerKind.BlittableValue)
                                return MarshallerKind.BlittableArray;
                            else
                                return MarshallerKind.Array;
                        }

                    case NativeTypeKind.ByValArray:         // fix sized array
                        {
                            var arrayType = (ArrayType)type;
                            elementMarshallerKind = GetArrayElementMarshallerKind(
                                arrayType,
                                marshalAs,
                                isAnsi);

                            // If element is invalid type, the array itself is invalid
                            if (elementMarshallerKind == MarshallerKind.Invalid)
                                return MarshallerKind.Invalid;

                            if (elementMarshallerKind == MarshallerKind.AnsiChar)
                                return MarshallerKind.ByValAnsiCharArray;
                            else
                                return MarshallerKind.ByValArray;
                        }

                    default:
                        return MarshallerKind.Invalid;
                }
            }
            else if (type.IsPointer)
            {
                type = type.GetParameterType();

                if (type.IsValueType && !type.IsPrimitive && !type.IsEnum && !isField
                    && HasCopyConstructorCustomModifier(parameterIndex, customModifierData))
                {
                    return MarshallerKind.BlittableValueClassWithCopyCtor;
                }

                if (nativeType == NativeTypeKind.Default)
                    return MarshallerKind.BlittableValue;
                else
                    return MarshallerKind.Invalid;
            }
            else if (type.IsFunctionPointer)
            {
                if (nativeType == NativeTypeKind.Func || nativeType == NativeTypeKind.Default)
                    return MarshallerKind.BlittableValue;
                else
                    return MarshallerKind.Invalid;
            }
            else if (type.IsDelegate || InteropTypes.IsSystemDelegate(context, type) || InteropTypes.IsSystemMulticastDelegate(context, type))
            {
                if (type.HasInstantiation)
                {
                    // Generic types cannot be marshaled.
                    return MarshallerKind.Invalid;
                }

                if (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Func)
                    return MarshallerKind.FunctionPointer;
                else
                    return MarshallerKind.Invalid;
            }
            else if (type.IsString)
            {
                switch (nativeType)
                {
                    case NativeTypeKind.LPWStr:
                        return MarshallerKind.UnicodeString;

                    case NativeTypeKind.LPStr:
                        return MarshallerKind.AnsiString;

                    case NativeTypeKind.LPUTF8Str:
                        return MarshallerKind.UTF8String;

                    case NativeTypeKind.LPTStr:
                        return MarshallerKind.UnicodeString;

                    case NativeTypeKind.ByValTStr:
                        if (isAnsi)
                        {
                            elementMarshallerKind = MarshallerKind.AnsiChar;
                            return MarshallerKind.ByValAnsiString;
                        }
                        else
                        {
                            elementMarshallerKind = MarshallerKind.UnicodeChar;
                            return MarshallerKind.ByValUnicodeString;
                        }

                    case NativeTypeKind.TBStr:
                    case NativeTypeKind.BStr:
                        return MarshallerKind.BSTRString;

                    case NativeTypeKind.AnsiBStr:
                        return MarshallerKind.AnsiBSTRString;

                    case NativeTypeKind.CustomMarshaler:
                        return MarshallerKind.CustomMarshaler;

                    case NativeTypeKind.Default:
                        if (isAnsi)
                            return MarshallerKind.AnsiString;
                        else
                            return MarshallerKind.UnicodeString;

                    default:
                        return MarshallerKind.Invalid;
                }
            }
            else if (type.IsObject)
            {
                if (nativeType == NativeTypeKind.AsAny && isField)
                    return MarshallerKind.FailedTypeLoad;
                if (nativeType == NativeTypeKind.AsAny)
                    return isAnsi ? MarshallerKind.AsAnyA : MarshallerKind.AsAnyW;
                else
                if (context.Target.IsWindows)
                {
                    if ((isField && nativeType == NativeTypeKind.Default)
                        || nativeType == NativeTypeKind.Intf
                        || nativeType == NativeTypeKind.IUnknown)
                        return MarshallerKind.ComInterface;
                    else
                        return MarshallerKind.Variant;
                }
                else
                    return MarshallerKind.Invalid;
            }
            else if (InteropTypes.IsStringBuilder(context, type))
            {
                switch (nativeType)
                {
                    case NativeTypeKind.Default:
                        if (isAnsi)
                        {
                            return MarshallerKind.AnsiStringBuilder;
                        }
                        else
                        {
                            return MarshallerKind.UnicodeStringBuilder;
                        }

                    case NativeTypeKind.LPStr:
                        return MarshallerKind.AnsiStringBuilder;

                    case NativeTypeKind.LPWStr:
                        return MarshallerKind.UnicodeStringBuilder;
                    default:
                        return MarshallerKind.Invalid;
                }
            }
            else if (InteropTypes.IsSafeHandle(context, type))
            {
                if (nativeType == NativeTypeKind.Default)
                    return MarshallerKind.SafeHandle;
                else
                    return MarshallerKind.Invalid;
            }
            else if (InteropTypes.IsCriticalHandle(context, type))
            {
                if (nativeType == NativeTypeKind.Default)
                    return MarshallerKind.CriticalHandle;
                else
                    return MarshallerKind.Invalid;
            }
            else if (type is MetadataType mdType && mdType.HasLayout())
            {
                if (type.HasInstantiation)
                {
                    // Generic types cannot be marshaled.
                    return MarshallerKind.Invalid;
                }

                if (!isField && nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.LPStruct)
                    return MarshallerKind.LayoutClassPtr;
                else if (isField && (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Struct))
                    return MarshallerKind.LayoutClass;
                else
                    return MarshallerKind.Invalid;
            }
            else if (type.IsInterface)
            {
                if (context.Target.IsWindows)
                    return MarshallerKind.ComInterface;
                else
                    return MarshallerKind.Invalid;
            }
            else
            {
                return MarshallerKind.Invalid;
            }
        }