Ejemplo n.º 1
0
        public static bool IsMarshallingRequired(MethodSignature methodSig, ParameterMetadata[] paramMetadata)
        {
            for (int i = 0, paramIndex = 0; i < methodSig.Length + 1; i++)
            {
                ParameterMetadata parameterMetadata = (paramIndex == paramMetadata.Length || i < paramMetadata[paramIndex].Index) ?
                                                      new ParameterMetadata(i, ParameterMetadataAttributes.None, null) :
                                                      paramMetadata[paramIndex++];

                TypeDesc parameterType = (i == 0) ? methodSig.ReturnType : methodSig[i - 1];  //first item is the return type

                MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(
                    parameterType,
                    parameterMetadata.MarshalAsDescriptor,
                    parameterMetadata.Return,
                    isAnsi: true,
                    MarshallerType.Argument,
                    out MarshallerKind elementMarshallerKind);

                if (IsMarshallingRequired(marshallerKind))
                {
                    return(true);
                }
            }

            return(false);
        }
Ejemplo n.º 2
0
        private static Marshaller CreateMarshallerInternal(MarshallerKind kind)
        {
            switch (kind)
            {
            case MarshallerKind.BlittableValue:
                return(new BlittableValueMarshaller());

            case MarshallerKind.BlittableArray:
                return(new BlittableArrayMarshaller());

            case MarshallerKind.BlittableByRef:
                return(new BlittableByRefMarshaller());

            case MarshallerKind.Bool:
                return(new BooleanMarshaller());

            case MarshallerKind.String:
                return(new StringMarshaller());

            case MarshallerKind.SafeHandle:
                return(new SafeHandleMarshaller());

            case MarshallerKind.StringBuilder:
                return(new StringBuilderMarshaller());

            case MarshallerKind.VoidReturn:
                return(new VoidReturnMarshaller());

            default:
                throw new NotSupportedException();
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Returns true if this type has a common representation in both managed and unmanaged memory
        /// and does not require special handling by the interop marshaler.
        /// </summary>
        public static bool IsBlittableType(TypeDesc type)
        {
            if (!type.IsDefType)
            {
                return false;
            }

            TypeDesc baseType = type.BaseType;
            bool hasNonTrivialParent = baseType != null
                && !baseType.IsWellKnownType(WellKnownType.Object)
                && !baseType.IsWellKnownType(WellKnownType.ValueType);

            if (hasNonTrivialParent && !IsBlittableType(baseType))
            {
                return false;
            }

            var mdType = (MetadataType)type;

            if (!mdType.IsSequentialLayout && !mdType.IsExplicitLayout)
            {
                return false;
            }

            foreach (FieldDesc field in type.GetFields())
            {
                if (field.IsStatic)
                {
                    continue;
                }

#if READYTORUN
                if (!field.FieldType.IsValueType)
                {
                    // Types with fields of non-value types cannot be blittable
                    // This check prevents possible infinite recursion where GetMarshallerKind would call back to IsBlittable e.g. for
                    // the case of classes with pointer members to the class itself.
                    return false;
                }
#endif

                MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(
                    field.FieldType,
                    field.GetMarshalAsDescriptor(),
                    isReturn: false,
                    isAnsi: mdType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass,
                    MarshallerType.Field,
                    elementMarshallerKind: out var _);

                if (marshallerKind != MarshallerKind.Enum
                    && marshallerKind != MarshallerKind.BlittableValue
                    && marshallerKind != MarshallerKind.BlittableStruct
                    && marshallerKind != MarshallerKind.UnicodeChar)
                {
                    return false;
                }
            }

            return true;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Returns true if this type has a common representation in both managed and unmanaged memory
        /// and does not require special handling by the interop marshaler.
        /// </summary>
        public static bool IsBlittableType(TypeDesc type)
        {
            if (!type.IsDefType)
            {
                return(false);
            }

            DefType baseType            = type.BaseType;
            bool    hasNonTrivialParent = baseType != null &&
                                          !baseType.IsWellKnownType(WellKnownType.Object) &&
                                          !baseType.IsWellKnownType(WellKnownType.ValueType);

            // Type is blittable only if parent is also blittable and is not empty.
            if (hasNonTrivialParent && (!IsBlittableType(baseType) || baseType.IsZeroSizedReferenceType))
            {
                return(false);
            }

            var mdType = (MetadataType)type;

            if (!mdType.IsSequentialLayout && !mdType.IsExplicitLayout)
            {
                return(false);
            }

            foreach (FieldDesc field in type.GetFields())
            {
                if (field.IsStatic)
                {
                    continue;
                }

                MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(
                    field.FieldType,
                    parameterIndex: null,
                    customModifierData: null,
                    field.GetMarshalAsDescriptor(),
                    isReturn: false,
                    isAnsi: mdType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass,
                    MarshallerType.Field,
                    elementMarshallerKind: out var _);

                if (marshallerKind != MarshallerKind.Enum &&
                    marshallerKind != MarshallerKind.BlittableValue &&
                    marshallerKind != MarshallerKind.BlittableStruct &&
                    marshallerKind != MarshallerKind.UnicodeChar)
                {
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Returns true if this type has a common representation in both managed and unmanaged memory
        /// and does not require special handling by the interop marshaler.
        /// </summary>
        public static bool IsBlittableType(TypeDesc type)
        {
            if (!type.IsDefType)
            {
                return(false);
            }

            TypeDesc baseType            = type.BaseType;
            bool     hasNonTrivialParent = baseType != null &&
                                           !baseType.IsWellKnownType(WellKnownType.Object) &&
                                           !baseType.IsWellKnownType(WellKnownType.ValueType);

            if (hasNonTrivialParent && !IsBlittableType(baseType))
            {
                return(false);
            }

            var mdType = (MetadataType)type;

            if (!mdType.IsSequentialLayout && !mdType.IsExplicitLayout)
            {
                return(false);
            }

            foreach (FieldDesc field in type.GetFields())
            {
                if (field.IsStatic)
                {
                    continue;
                }

                MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(
                    field.FieldType,
                    field.GetMarshalAsDescriptor(),
                    isReturn: false,
                    isAnsi: mdType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass,
                    MarshallerType.Field,
                    elementMarshallerKind: out var _);

                if (marshallerKind != MarshallerKind.Enum &&
                    marshallerKind != MarshallerKind.BlittableValue &&
                    marshallerKind != MarshallerKind.BlittableStruct &&
                    marshallerKind != MarshallerKind.UnicodeChar)
                {
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Create a marshaller
        /// </summary>
        /// <param name="parameterType">type of the parameter to marshal</param>
        /// <param name="pInvokeMethodData">PInvoke Method specific marshal data</param>
        /// <param name="pInvokeParameterdata">PInvoke parameter specific marshal data</param>
        /// <returns>The  created Marshaller</returns>
        public static Marshaller CreateMarshaller(TypeDesc parameterType, PInvokeMethodData pInvokeMethodData, ParameterMetadata pInvokeParameterdata)
        {
            MarshallerKind marshallerKind = GetMarshallerKind(parameterType, pInvokeParameterdata.MarshalAsDescriptor, pInvokeMethodData, pInvokeParameterdata.Return);

            // Create the marshaller based on MarshallerKind
            Marshaller marshaller = Marshaller.CreateMarshallerInternal(marshallerKind);

            marshaller.PInvokeMethodData        = pInvokeMethodData;
            marshaller.PInvokeParameterMetadata = pInvokeParameterdata;
            marshaller.MarshallerKind           = marshallerKind;
            marshaller.NativeType  = null;
            marshaller.ManagedType = parameterType;

            return(marshaller);
        }
Ejemplo n.º 7
0
        internal static TypeDesc GetNativeMethodParameterType(TypeDesc type, MarshalAsDescriptor marshalAs, InteropStateManager interopStateManager, bool isReturn, bool isAnsi)
        {
            MarshallerKind elementMarshallerKind;
            MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(type,
                                                                             marshalAs,
                                                                             isReturn,
                                                                             isAnsi,
                                                                             MarshallerType.Argument,
                                                                             out elementMarshallerKind);

            return(GetNativeTypeFromMarshallerKind(type,
                                                   marshallerKind,
                                                   elementMarshallerKind,
                                                   interopStateManager,
                                                   marshalAs));
        }
Ejemplo n.º 8
0
        internal static TypeDesc GetNativeStructFieldType(TypeDesc type, MarshalAsDescriptor marshalAs, InteropStateManager interopStateManager, bool isAnsi)
        {
            MarshallerKind elementMarshallerKind;
            MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(type,
                                                                             marshalAs,
                                                                             false,  /*  isReturn */
                                                                             isAnsi, /*    isAnsi */
                                                                             MarshallerType.Field,
                                                                             out elementMarshallerKind);

            return(GetNativeTypeFromMarshallerKind(type,
                                                   marshallerKind,
                                                   elementMarshallerKind,
                                                   interopStateManager,
                                                   marshalAs));
        }
Ejemplo n.º 9
0
        protected static Marshaller CreateMarshaller(MarshallerKind kind)
        {
            switch (kind)
            {
            case MarshallerKind.Enum:
            case MarshallerKind.BlittableValue:
            case MarshallerKind.BlittableStruct:
            case MarshallerKind.UnicodeChar:
                return(new BlittableValueMarshaller());

            case MarshallerKind.BlittableStructPtr:
                return(new BlittableStructPtrMarshaller());

            case MarshallerKind.BlittableArray:
                return(new BlittableArrayMarshaller());

            case MarshallerKind.Bool:
            case MarshallerKind.CBool:
                return(new BooleanMarshaller());

            case MarshallerKind.AnsiString:
                return(new AnsiStringMarshaller());

            case MarshallerKind.UTF8String:
                return(new UTF8StringMarshaller());

            case MarshallerKind.SafeHandle:
                return(new SafeHandleMarshaller());

            case MarshallerKind.UnicodeString:
                return(new UnicodeStringMarshaller());

            case MarshallerKind.VoidReturn:
                return(new VoidReturnMarshaller());

            case MarshallerKind.FunctionPointer:
                return(new DelegateMarshaller());

            default:
                // ensures we don't throw during create marshaller. We will throw NSE
                // during EmitIL which will be handled.
                return(new NotSupportedMarshaller());
            }
        }
Ejemplo n.º 10
0
        protected static Marshaller CreateMarshaller(MarshallerKind kind)
        {
            // ReadyToRun only supports emitting IL for blittable types
            switch (kind)
            {
            case MarshallerKind.Enum:
            case MarshallerKind.BlittableValue:
            case MarshallerKind.BlittableStruct:
            case MarshallerKind.UnicodeChar:
                return(new BlittableValueMarshaller());

            case MarshallerKind.VoidReturn:
                return(new VoidReturnMarshaller());

            default:
                // ensures we don't throw during create marshaller. We will throw NSE
                // during EmitIL which will be handled.
                return(new NotSupportedMarshaller());
            }
        }
Ejemplo n.º 11
0
        private static Marshaller CreateMarshallerInternal(MarshallerKind kind)
        {
            switch (kind)
            {
            case MarshallerKind.Enum:
            case MarshallerKind.BlittableValue:
            case MarshallerKind.BlittableStruct:
            case MarshallerKind.UnicodeChar:
                return(new BlittableValueMarshaller());

            case MarshallerKind.Array:
            case MarshallerKind.BlittableArray:
                return(new BlittableArrayMarshaller());

            case MarshallerKind.Bool:
                return(new BooleanMarshaller());

            case MarshallerKind.AnsiString:
                return(new AnsiStringMarshaller());

            case MarshallerKind.UnicodeString:
                return(new UnicodeStringMarshaller());

            case MarshallerKind.SafeHandle:
                return(new SafeHandleMarshaller());

            case MarshallerKind.UnicodeStringBuilder:
                return(new UnicodeStringBuilderMarshaller());

            case MarshallerKind.VoidReturn:
                return(new VoidReturnMarshaller());

            default:
                throw new NotSupportedException();
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Create a marshaller
        /// </summary>
        /// <param name="parameterType">type of the parameter to marshal</param>
        /// <param name="pInvokeMethodData">PInvoke Method specific marshal data</param>
        /// <param name="pInvokeParameterdata">PInvoke parameter specific marshal data</param>
        /// <returns>The  created Marshaller</returns>
        public static Marshaller CreateMarshaller(TypeDesc parameterType, PInvokeMethodData pInvokeMethodData, ParameterMetadata pInvokeParameterdata)
        {
            MarshallerKind marshallerKind = GetMarshallerKind(parameterType,
                                                              pInvokeParameterdata,
                                                              pInvokeMethodData,
                                                              isField: false);

            // Create the marshaller based on MarshallerKind
            Marshaller marshaller = Marshaller.CreateMarshallerInternal(marshallerKind);

            marshaller.PInvokeMethodData        = pInvokeMethodData;
            marshaller.PInvokeParameterMetadata = pInvokeParameterdata;
            marshaller.MarshallerKind           = marshallerKind;
            marshaller.NativeParameterType      = null;
            marshaller.ManagedParameterType     = parameterType;
            marshaller.Optional = pInvokeParameterdata.Optional;
            marshaller.Return   = pInvokeParameterdata.Return;
            marshaller.IsByRef  = parameterType.IsByRef;
            marshaller.In       = pInvokeParameterdata.In;
            //
            // Desktop ignores [Out] on marshaling scenarios where they don't make sense (such as passing
            // value types and string as [out] without byref).
            //
            if (parameterType.IsByRef)
            {
                // Passing as [Out] by ref is valid
                marshaller.Out = pInvokeParameterdata.Out;
            }
            else
            {
                // Passing as [Out] is valid only if it is not ValueType nor string
                if (!parameterType.IsValueType && !parameterType.IsString)
                {
                    marshaller.Out = pInvokeParameterdata.Out;
                }
            }

            if (!marshaller.In && !marshaller.Out)
            {
                //
                // Rules for in/out
                // 1. ByRef args: [in]/[out] implied by default
                // 2. StringBuilder: [in, out] by default
                // 3. non-ByRef args: [In] is implied if no [In]/[Out] is specified
                //
                if (parameterType.IsByRef)
                {
                    marshaller.In  = true;
                    marshaller.Out = true;
                }
                else if (pInvokeMethodData.IsStringBuilder(parameterType))
                {
                    marshaller.In  = true;
                    marshaller.Out = true;
                }
                else
                {
                    marshaller.In = true;
                }
            }
            return(marshaller);
        }
Ejemplo n.º 13
0
        internal static InlineArrayCandidate GetInlineArrayCandidate(TypeDesc managedElementType, MarshallerKind elementMarshallerKind, InteropStateManager interopStateManager, MarshalAsDescriptor marshalAs)
        {
            TypeDesc nativeType = GetNativeTypeFromMarshallerKind(
                managedElementType,
                elementMarshallerKind,
                MarshallerKind.Unknown,
                interopStateManager,
                null);

            var elementNativeType = nativeType as MetadataType;

            if (elementNativeType == null)
            {
                Debug.Assert(nativeType.IsPointer || nativeType.IsFunctionPointer);

                // If it is a pointer type we will create InlineArray for IntPtr
                elementNativeType = (MetadataType)managedElementType.Context.GetWellKnownType(WellKnownType.IntPtr);
            }
            Debug.Assert(marshalAs != null && marshalAs.SizeConst.HasValue);

            // if SizeConst is not specified, we will default to 1.
            // the marshaller will throw appropriate exception
            uint size = 1;

            if (marshalAs.SizeConst.HasValue)
            {
                size = marshalAs.SizeConst.Value;
            }
            return(new InlineArrayCandidate(elementNativeType, size));
        }
Ejemplo n.º 14
0
        internal static InlineArrayCandidate GetInlineArrayCandidate(TypeDesc managedElementType, MarshallerKind elementMarshallerKind, InteropStateManager interopStateManager, MarshalAsDescriptor marshalAs)
        {
            var elementNativeType = (MetadataType)GetNativeTypeFromMarshallerKind(
                managedElementType,
                elementMarshallerKind,
                MarshallerKind.Unknown,
                interopStateManager,
                null);

            Debug.Assert(marshalAs.SizeConst.HasValue);

            // if SizeConst is not specified, we will default to 1.
            // the marshaller will throw appropriate exception
            uint size = 1;

            if (marshalAs.SizeConst.HasValue)
            {
                size = marshalAs.SizeConst.Value;
            }
            return(new InlineArrayCandidate(elementNativeType, size));
        }
Ejemplo n.º 15
0
        internal static MarshallerKind GetMarshallerKind(
            TypeDesc type,
            MarshalAsDescriptor marshalAs,
            bool isReturn,
            bool isAnsi,
            MarshallerType marshallerType,
            out MarshallerKind elementMarshallerKind)
        {
            elementMarshallerKind = MarshallerKind.Invalid;

            bool isByRef = false;

            if (type.IsByRef)
            {
                isByRef = true;

                type = type.GetParameterType();

                // Compat note: CLR allows ref returning blittable structs for IJW
                if (isReturn)
                {
                    return(MarshallerKind.Invalid);
                }
            }
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Default;
            bool isField = marshallerType == MarshallerType.Field;

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

            //
            // Determine MarshalerKind
            //
            // This mostly resembles desktop CLR and .NET Native code as we need to match their behavior
            //
            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);

                    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 && !isReturn)
                    {
                        return(MarshallerKind.BlittableStructPtr);
                    }
                    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 && !isReturn)
                    {
                        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 (type.HasInstantiation)
                {
                    // Generic types cannot be marshaled.
                    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 READYTORUN
                // We don't want the additional test/maintenance cost of this in R2R.
                if (isByRef)
                {
                    return(MarshallerKind.Invalid);
                }
#else
                _ = isByRef;
#endif

                if (nativeType == NativeTypeKind.Default)
                {
                    nativeType = NativeTypeKind.Array;
                }

                switch (nativeType)
                {
                case NativeTypeKind.Array:
                {
                    if (isField || isReturn)
                    {
                        return(MarshallerKind.Invalid);
                    }

                    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)
            {
                TypeDesc parameterType = ((PointerType)type).ParameterType;

                if ((!parameterType.IsEnum &&
                     !parameterType.IsPrimitive &&
                     !MarshalUtils.IsBlittableType(parameterType)) ||
                    parameterType.IsGCPointer)
                {
                    // Pointers cannot reference marshaled structures.  Use ByRef instead.
                    return(MarshallerKind.Invalid);
                }

                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)
            {
                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.Default:
                    if (isAnsi)
                    {
                        return(MarshallerKind.AnsiString);
                    }
                    else
                    {
                        return(MarshallerKind.UnicodeString);
                    }

                default:
                    return(MarshallerKind.Invalid);
                }
            }
            else if (type.IsObject)
            {
                if (nativeType == NativeTypeKind.AsAny)
                {
                    return(isAnsi ? MarshallerKind.AsAnyA : MarshallerKind.AsAnyW);
                }
                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);
                }
            }
Ejemplo n.º 16
0
        protected static Marshaller CreateMarshaller(MarshallerKind kind)
        {
            switch (kind)
            {
            case MarshallerKind.Enum:
            case MarshallerKind.BlittableValue:
            case MarshallerKind.BlittableStruct:
            case MarshallerKind.UnicodeChar:
                return(new BlittableValueMarshaller());

            case MarshallerKind.BlittableStructPtr:
                return(new BlittableStructPtrMarshaller());

            case MarshallerKind.AnsiChar:
                return(new AnsiCharMarshaller());

            case MarshallerKind.Array:
                return(new ArrayMarshaller());

            case MarshallerKind.BlittableArray:
                return(new BlittableArrayMarshaller());

            case MarshallerKind.Bool:
            case MarshallerKind.CBool:
                return(new BooleanMarshaller());

            case MarshallerKind.VariantBool:
                return(new BooleanMarshaller((short)-1));

            case MarshallerKind.AnsiString:
                return(new AnsiStringMarshaller());

            case MarshallerKind.UTF8String:
                return(new UTF8StringMarshaller());

            case MarshallerKind.UnicodeString:
                return(new UnicodeStringMarshaller());

            case MarshallerKind.AnsiBSTRString:
                return(new AnsiBSTRStringMarshaller());

            case MarshallerKind.BSTRString:
                return(new BSTRStringMarshaller());

            case MarshallerKind.SafeHandle:
                return(new SafeHandleMarshaller());

            case MarshallerKind.UnicodeStringBuilder:
                return(new StringBuilderMarshaller(isAnsi: false));

            case MarshallerKind.AnsiStringBuilder:
                return(new StringBuilderMarshaller(isAnsi: true));

            case MarshallerKind.VoidReturn:
                return(new VoidReturnMarshaller());

            case MarshallerKind.FunctionPointer:
                return(new DelegateMarshaller());

            case MarshallerKind.Struct:
            case MarshallerKind.Decimal:
                return(new StructMarshaller());

            case MarshallerKind.ByValAnsiString:
                return(new ByValAnsiStringMarshaller());

            case MarshallerKind.ByValUnicodeString:
                return(new ByValUnicodeStringMarshaller());

            case MarshallerKind.ByValAnsiCharArray:
            case MarshallerKind.ByValArray:
                return(new ByValArrayMarshaller());

            case MarshallerKind.AnsiCharArray:
                return(new AnsiCharArrayMarshaller());

            case MarshallerKind.HandleRef:
                return(new HandleRefMarshaller());

            case MarshallerKind.LayoutClass:
                return(new LayoutClassMarshaler());

            case MarshallerKind.LayoutClassPtr:
                return(new LayoutClassPtrMarshaller());

            case MarshallerKind.AsAnyA:
                return(new AsAnyMarshaller(isAnsi: true));

            case MarshallerKind.AsAnyW:
                return(new AsAnyMarshaller(isAnsi: false));

            case MarshallerKind.ComInterface:
                return(new ComInterfaceMarshaller());

            case MarshallerKind.OleDateTime:
                return(new OleDateTimeMarshaller());

            case MarshallerKind.OleCurrency:
                return(new OleCurrencyMarshaller());

            case MarshallerKind.FailedTypeLoad:
                return(new FailedTypeLoadMarshaller());

            case MarshallerKind.Variant:
                return(new VariantMarshaller());

            case MarshallerKind.CustomMarshaler:
                return(new CustomTypeMarshaller());

            default:
                // ensures we don't throw during create marshaller. We will throw NSE
                // during EmitIL which will be handled and an Exception method body
                // will be emitted.
                return(new NotSupportedMarshaller());
            }
        }
Ejemplo n.º 17
0
        internal static MarshallerKind GetMarshallerKind(
            TypeDesc type,
            MarshalAsDescriptor marshalAs,
            bool isReturn,
            bool isAnsi,
            MarshallerType marshallerType,
            out MarshallerKind elementMarshallerKind)
        {
            elementMarshallerKind = MarshallerKind.Invalid;

            bool isByRef = false;

            if (type.IsByRef)
            {
                isByRef = true;

                type = type.GetParameterType();

                // Compat note: CLR allows ref returning blittable structs for IJW
                if (isReturn)
                {
                    return(MarshallerKind.Invalid);
                }
            }
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Default;
            bool isField = marshallerType == MarshallerType.Field;

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

            //
            // Determine MarshalerKind
            //
            // This mostly resembles .NET Framework CLR and .NET Native code as we need to match their behavior
            //
            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);

                    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 && !isReturn)
                    {
                        return(MarshallerKind.BlittableStructPtr);
                    }
                    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 && !isReturn)
                    {
                        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);
                }

                bool isBlittable = MarshalUtils.IsBlittableType(type);

                // Blittable generics are allowed to be marshalled with the following exceptions:
                // * ByReference<T>: This represents an interior pointer and is not actually blittable
                // * Nullable<T>: We don't want to be locked into the default behavior as we may want special handling later
                // * Vector64<T>: Represents the __m64 ABI primitive which requires currently unimplemented handling
                // * Vector128<T>: Represents the __m128 ABI primitive which requires currently unimplemented handling
                // * Vector256<T>: Represents the __m256 ABI primitive which requires currently unimplemented handling
                // * Vector<T>: Has a variable size (either __m128 or __m256) and isn't readily usable for inteorp scenarios

                if (type.HasInstantiation && (!isBlittable ||
                                              InteropTypes.IsSystemByReference(context, type) ||
                                              InteropTypes.IsSystemNullable(context, type) ||
                                              InteropTypes.IsSystemRuntimeIntrinsicsVector64T(context, type) ||
                                              InteropTypes.IsSystemRuntimeIntrinsicsVector128T(context, type) ||
                                              InteropTypes.IsSystemRuntimeIntrinsicsVector256T(context, type) ||
                                              InteropTypes.IsSystemNumericsVectorT(context, type)))
                {
                    // Generic types cannot be marshaled.
                    return(MarshallerKind.Invalid);
                }

                if (isBlittable)
                {
                    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 READYTORUN
                // We don't want the additional test/maintenance cost of this in R2R.
                if (isByRef)
                {
                    return(MarshallerKind.Invalid);
                }
#else
                _ = isByRef;
#endif

                if (nativeType == NativeTypeKind.Default)
                {
                    nativeType = NativeTypeKind.Array;
                }

                switch (nativeType)
                {
                case NativeTypeKind.Array:
                {
                    if (isField || isReturn)
                    {
                        return(MarshallerKind.Invalid);
                    }

                    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)
            {
#if READYTORUN
                TypeDesc parameterType = ((PointerType)type).ParameterType;

                if ((!parameterType.IsEnum &&
                     !parameterType.IsPrimitive &&
                     !MarshalUtils.IsBlittableType(parameterType)) ||
                    parameterType.IsGCPointer)
                {
                    // Pointers cannot reference marshaled structures.  Use ByRef instead.
                    return(MarshallerKind.Invalid);
                }
#else
                // Do not bother enforcing the above artificial restriction
                // See https://github.com/dotnet/coreclr/issues/27800
#endif

                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)
            {
                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.Default:
                    if (isAnsi)
                    {
                        return(MarshallerKind.AnsiString);
                    }
                    else
                    {
                        return(MarshallerKind.UnicodeString);
                    }

                default:
                    return(MarshallerKind.Invalid);
                }
            }
            else if (type.IsObject)
            {
                if (nativeType == NativeTypeKind.AsAny)
                {
                    return(isAnsi ? MarshallerKind.AsAnyA : MarshallerKind.AsAnyW);
                }
                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);
                }
            }
Ejemplo n.º 18
0
        internal static TypeDesc GetNativeTypeFromMarshallerKind(TypeDesc type,
                                                                 MarshallerKind kind,
                                                                 MarshallerKind elementMarshallerKind,
                                                                 InteropStateManager interopStateManager,
                                                                 MarshalAsDescriptor marshalAs,
                                                                 bool isArrayElement = false)
        {
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Invalid;

            if (marshalAs != null)
            {
                nativeType = isArrayElement ? marshalAs.ArraySubType : marshalAs.Type;
            }

            switch (kind)
            {
            case MarshallerKind.BlittableValue:
            {
                switch (nativeType)
                {
                case NativeTypeKind.I1:
                    return(context.GetWellKnownType(WellKnownType.SByte));

                case NativeTypeKind.U1:
                    return(context.GetWellKnownType(WellKnownType.Byte));

                case NativeTypeKind.I2:
                    return(context.GetWellKnownType(WellKnownType.Int16));

                case NativeTypeKind.U2:
                    return(context.GetWellKnownType(WellKnownType.UInt16));

                case NativeTypeKind.I4:
                    return(context.GetWellKnownType(WellKnownType.Int32));

                case NativeTypeKind.U4:
                    return(context.GetWellKnownType(WellKnownType.UInt32));

                case NativeTypeKind.I8:
                    return(context.GetWellKnownType(WellKnownType.Int64));

                case NativeTypeKind.U8:
                    return(context.GetWellKnownType(WellKnownType.UInt64));

                case NativeTypeKind.R4:
                    return(context.GetWellKnownType(WellKnownType.Single));

                case NativeTypeKind.R8:
                    return(context.GetWellKnownType(WellKnownType.Double));

                default:
                    return(type.UnderlyingType);
                }
            }

            case MarshallerKind.Bool:
                return(context.GetWellKnownType(WellKnownType.Int32));

            case MarshallerKind.CBool:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case MarshallerKind.Enum:
            case MarshallerKind.BlittableStruct:
            case MarshallerKind.Decimal:
            case MarshallerKind.VoidReturn:
                return(type);

            case MarshallerKind.Struct:
                return(interopStateManager.GetStructMarshallingNativeType((MetadataType)type));

            case MarshallerKind.BlittableStructPtr:
                return(type.MakePointerType());

            case MarshallerKind.HandleRef:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.UnicodeChar:
                if (nativeType == NativeTypeKind.U2)
                {
                    return(context.GetWellKnownType(WellKnownType.UInt16));
                }
                else
                {
                    return(context.GetWellKnownType(WellKnownType.Int16));
                }

            case MarshallerKind.OleDateTime:
                return(context.GetWellKnownType(WellKnownType.Double));

            case MarshallerKind.SafeHandle:
            case MarshallerKind.CriticalHandle:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.UnicodeString:
            case MarshallerKind.UnicodeStringBuilder:
                return(context.GetWellKnownType(WellKnownType.Char).MakePointerType());

            case MarshallerKind.AnsiString:
            case MarshallerKind.AnsiStringBuilder:
                return(context.GetWellKnownType(WellKnownType.Byte).MakePointerType());

            case MarshallerKind.BlittableArray:
            case MarshallerKind.Array:
            case MarshallerKind.AnsiCharArray:
            {
                ArrayType arrayType = type as ArrayType;
                Debug.Assert(arrayType != null, "Expecting array");

                //
                // We need to construct the unsafe array from the right unsafe array element type
                //
                TypeDesc elementNativeType = GetNativeTypeFromMarshallerKind(
                    arrayType.ElementType,
                    elementMarshallerKind,
                    MarshallerKind.Unknown,
                    interopStateManager,
                    marshalAs,
                    isArrayElement: true);

                return(elementNativeType.MakePointerType());
            }

            case MarshallerKind.AnsiChar:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case MarshallerKind.FunctionPointer:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.ByValUnicodeString:
            case MarshallerKind.ByValAnsiString:
            {
                var inlineArrayCandidate = GetInlineArrayCandidate(context.GetWellKnownType(WellKnownType.Char), elementMarshallerKind, interopStateManager, marshalAs);
                return(interopStateManager.GetInlineArrayType(inlineArrayCandidate));
            }

            case MarshallerKind.ByValAnsiCharArray:
            case MarshallerKind.ByValArray:
            {
                ArrayType arrayType = type as ArrayType;
                Debug.Assert(arrayType != null, "Expecting array");

                var inlineArrayCandidate = GetInlineArrayCandidate(arrayType.ElementType, elementMarshallerKind, interopStateManager, marshalAs);

                return(interopStateManager.GetInlineArrayType(inlineArrayCandidate));
            }

            case MarshallerKind.Unknown:
            default:
                throw new NotSupportedException();
            }
        }
Ejemplo n.º 19
0
        internal static TypeDesc GetNativeTypeFromMarshallerKind(TypeDesc type,
                                                                 MarshallerKind kind,
                                                                 MarshallerKind elementMarshallerKind,
#if !READYTORUN
                                                                 InteropStateManager interopStateManager,
#endif
                                                                 MarshalAsDescriptor marshalAs,
                                                                 bool isArrayElement = false)
        {
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Default;

            if (marshalAs != null)
            {
                nativeType = isArrayElement ? marshalAs.ArraySubType : marshalAs.Type;
            }

            switch (kind)
            {
            case MarshallerKind.BlittableValue:
            {
                switch (nativeType)
                {
                case NativeTypeKind.I1:
                    return(context.GetWellKnownType(WellKnownType.SByte));

                case NativeTypeKind.U1:
                    return(context.GetWellKnownType(WellKnownType.Byte));

                case NativeTypeKind.I2:
                    return(context.GetWellKnownType(WellKnownType.Int16));

                case NativeTypeKind.U2:
                    return(context.GetWellKnownType(WellKnownType.UInt16));

                case NativeTypeKind.I4:
                    return(context.GetWellKnownType(WellKnownType.Int32));

                case NativeTypeKind.U4:
                    return(context.GetWellKnownType(WellKnownType.UInt32));

                case NativeTypeKind.I8:
                    return(context.GetWellKnownType(WellKnownType.Int64));

                case NativeTypeKind.U8:
                    return(context.GetWellKnownType(WellKnownType.UInt64));

                case NativeTypeKind.R4:
                    return(context.GetWellKnownType(WellKnownType.Single));

                case NativeTypeKind.R8:
                    return(context.GetWellKnownType(WellKnownType.Double));

                default:
                    return(type.UnderlyingType);
                }
            }

            case MarshallerKind.Bool:
                return(context.GetWellKnownType(WellKnownType.Int32));

            case MarshallerKind.CBool:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case MarshallerKind.VariantBool:
                return(context.GetWellKnownType(WellKnownType.Int16));

            case MarshallerKind.Enum:
            case MarshallerKind.BlittableStruct:
            case MarshallerKind.Decimal:
            case MarshallerKind.VoidReturn:
                return(type);

#if !READYTORUN
            case MarshallerKind.Struct:
            case MarshallerKind.LayoutClass:
                Debug.Assert(interopStateManager is not null, "An InteropStateManager is required to look up the native representation of a non-blittable struct or class with layout.");
                return(interopStateManager.GetStructMarshallingNativeType((MetadataType)type));
#endif

            case MarshallerKind.BlittableStructPtr:
                return(type.MakePointerType());

            case MarshallerKind.HandleRef:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.UnicodeChar:
                if (nativeType == NativeTypeKind.U2)
                {
                    return(context.GetWellKnownType(WellKnownType.UInt16));
                }
                else
                {
                    return(context.GetWellKnownType(WellKnownType.Int16));
                }

            case MarshallerKind.OleDateTime:
                return(context.GetWellKnownType(WellKnownType.Double));

            case MarshallerKind.FailedTypeLoad:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.SafeHandle:
            case MarshallerKind.CriticalHandle:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.BSTRString:
            case MarshallerKind.UnicodeString:
            case MarshallerKind.UnicodeStringBuilder:
                return(context.GetWellKnownType(WellKnownType.Char).MakePointerType());

            case MarshallerKind.AnsiBSTRString:
            case MarshallerKind.AnsiString:
            case MarshallerKind.AnsiStringBuilder:
            case MarshallerKind.UTF8String:
                return(context.GetWellKnownType(WellKnownType.Byte).MakePointerType());

            case MarshallerKind.BlittableArray:
            case MarshallerKind.Array:
            case MarshallerKind.AnsiCharArray:
            {
                ArrayType arrayType = type as ArrayType;
                Debug.Assert(arrayType != null, "Expecting array");

                //
                // We need to construct the unsafe array from the right unsafe array element type
                //
                TypeDesc elementNativeType = GetNativeTypeFromMarshallerKind(
                    arrayType.ElementType,
                    elementMarshallerKind,
                    MarshallerKind.Unknown,
#if !READYTORUN
                    interopStateManager,
#endif
                    marshalAs,
                    isArrayElement: true);

                return(elementNativeType.MakePointerType());
            }

            case MarshallerKind.AnsiChar:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case MarshallerKind.FunctionPointer:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

#if !READYTORUN
            case MarshallerKind.ByValUnicodeString:
            case MarshallerKind.ByValAnsiString:
            {
                var inlineArrayCandidate = GetInlineArrayCandidate(context.GetWellKnownType(WellKnownType.Char), elementMarshallerKind, interopStateManager, marshalAs);
                return(interopStateManager.GetInlineArrayType(inlineArrayCandidate));
            }

            case MarshallerKind.ByValAnsiCharArray:
            case MarshallerKind.ByValArray:
            {
                ArrayType arrayType = type as ArrayType;
                Debug.Assert(arrayType != null, "Expecting array");

                var inlineArrayCandidate = GetInlineArrayCandidate(arrayType.ElementType, elementMarshallerKind, interopStateManager, marshalAs);

                return(interopStateManager.GetInlineArrayType(inlineArrayCandidate));
            }
#endif

            case MarshallerKind.LayoutClassPtr:
            case MarshallerKind.AsAnyA:
            case MarshallerKind.AsAnyW:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.ComInterface:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

#if !READYTORUN
            case MarshallerKind.Variant:
                return(InteropTypes.GetVariant(context));

            case MarshallerKind.CustomMarshaler:
                return(context.GetWellKnownType(WellKnownType.IntPtr));
#endif

            case MarshallerKind.OleCurrency:
                return(context.GetWellKnownType(WellKnownType.Int64));

            case MarshallerKind.Unknown:
            default:
                throw new NotSupportedException();
            }
        }
Ejemplo n.º 20
0
        internal static MarshallerKind GetMarshallerKind(
            TypeDesc type,
            MarshalAsDescriptor marshalAs,
            bool isReturn,
            bool isAnsi,
            MarshallerType marshallerType,
            out MarshallerKind elementMarshallerKind)
        {
            if (type.IsByRef)
            {
                type = type.GetParameterType();
            }
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Invalid;
            bool isField = marshallerType == MarshallerType.Field;

            if (marshalAs != null)
            {
                nativeType = (NativeTypeKind)marshalAs.Type;
            }


            elementMarshallerKind = MarshallerKind.Invalid;

            //
            // Determine MarshalerKind
            //
            // This mostly resembles desktop CLR and .NET Native code as we need to match their behavior
            //
            if (type.IsPrimitive)
            {
                switch (type.Category)
                {
                case TypeFlags.Void:
                    return(MarshallerKind.VoidReturn);

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

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

                    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.Invalid:
                        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.Invalid)
                    {
                        return(MarshallerKind.BlittableValue);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }

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

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

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

                case TypeFlags.IntPtr:
                case TypeFlags.UIntPtr:
                    if (nativeType == NativeTypeKind.Invalid)
                    {
                        return(MarshallerKind.BlittableValue);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }

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

                case TypeFlags.Double:
                    if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Invalid)
                    {
                        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.Invalid ||
                        nativeType == NativeTypeKind.Struct)
                    {
                        return(MarshallerKind.OleDateTime);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }
                }
                else if (InteropTypes.IsHandleRef(context, type))
                {
                    if (nativeType == NativeTypeKind.Invalid)
                    {
                        return(MarshallerKind.HandleRef);
                    }
                    else
                    {
                        return(MarshallerKind.Invalid);
                    }
                }

                switch (nativeType)
                {
                case NativeTypeKind.Invalid:
                case NativeTypeKind.Struct:
                    if (InteropTypes.IsSystemDecimal(context, type))
                    {
                        return(MarshallerKind.Decimal);
                    }
                    break;

                case NativeTypeKind.LPStruct:
                    if (InteropTypes.IsSystemGuid(context, type) ||
                        InteropTypes.IsSystemDecimal(context, type))
                    {
                        if (isField || isReturn)
                        {
                            return(MarshallerKind.Invalid);
                        }
                        else
                        {
                            return(MarshallerKind.BlittableStructPtr);
                        }
                    }
                    break;

                default:
                    return(MarshallerKind.Invalid);
                }

                if (type is MetadataType)
                {
                    MetadataType metadataType = (MetadataType)type;
                    // the struct type need to be either sequential or explicit. If it is
                    // auto layout we will throw exception.
                    if (!metadataType.IsSequentialLayout && !metadataType.IsExplicitLayout)
                    {
                        throw new InvalidProgramException("The specified structure " + metadataType.Name + " has invalid StructLayout information. It must be either Sequential or Explicit.");
                    }
                }

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

                switch (nativeType)
                {
                case NativeTypeKind.Array:
                {
                    if (isField || isReturn)
                    {
                        return(MarshallerKind.Invalid);
                    }

                    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.IsFunctionPointer)
            {
                if (nativeType == NativeTypeKind.Invalid)
                {
                    return(MarshallerKind.BlittableValue);
                }
                else
                {
                    return(MarshallerKind.Invalid);
                }
            }
            else if (type.IsDelegate)
            {
                if (nativeType == NativeTypeKind.Invalid || 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.LPTStr:
                    return(MarshallerKind.UnicodeString);

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

                case NativeTypeKind.Invalid:
                    if (isAnsi)
                    {
                        return(MarshallerKind.AnsiString);
                    }
                    else
                    {
                        return(MarshallerKind.UnicodeString);
                    }

                default:
                    return(MarshallerKind.Invalid);
                }
            }
            // else if (type.IsObject)
            // {
            //    if (nativeType == NativeTypeKind.Invalid)
            //        return MarshallerKind.Variant;
            //    else
            //        return MarshallerKind.Invalid;
            // }
            else if (InteropTypes.IsStringBuilder(context, type))
            {
                switch (nativeType)
                {
                case NativeTypeKind.Invalid:
                    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.Invalid)
                {
                    return(MarshallerKind.SafeHandle);
                }
                else
                {
                    return(MarshallerKind.Invalid);
                }
            }
            else if (InteropTypes.IsCriticalHandle(context, type))
            {
                if (nativeType == NativeTypeKind.Invalid)
                {
                    return(MarshallerKind.CriticalHandle);
                }
                else
                {
                    return(MarshallerKind.Invalid);
                }
            }
            else
            {
                return(MarshallerKind.Invalid);
            }
        }
Ejemplo n.º 21
0
        internal static MarshallerKind GetMarshallerKind(
            TypeDesc type,
            int?parameterIndex,
            EmbeddedSignatureData[] customModifierData,
            MarshalAsDescriptor marshalAs,
            bool isReturn,
            bool isAnsi,
            MarshallerType marshallerType,
            out MarshallerKind elementMarshallerKind)
        {
            elementMarshallerKind = MarshallerKind.Invalid;

            bool isByRef = false;

            if (type.IsByRef)
            {
                isByRef = true;

                type = type.GetParameterType();

                if (!type.IsPrimitive && type.IsValueType && marshallerType != MarshallerType.Field &&
                    HasCopyConstructorCustomModifier(parameterIndex, customModifierData))
                {
                    return(MarshallerKind.BlittableValueClassWithCopyCtor);
                }

                // Compat note: CLR allows ref returning blittable structs for IJW
                if (isReturn)
                {
                    return(MarshallerKind.Invalid);
                }
            }
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Default;
            bool isField = marshallerType == MarshallerType.Field;

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

            //
            // 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);
                }

                bool isBlittable = MarshalUtils.IsBlittableType(type);

                // Blittable generics are allowed to be marshalled with the following exceptions:
                // * ByReference<T>: This represents an interior pointer and is not actually blittable
                // * Nullable<T>: We don't want to be locked into the default behavior as we may want special handling later
                // * Vector64<T>: Represents the __m64 ABI primitive which requires currently unimplemented handling
                // * Vector128<T>: Represents the __m128 ABI primitive which requires currently unimplemented handling
                // * Vector256<T>: Represents the __m256 ABI primitive which requires currently unimplemented handling
                // * Vector<T>: Has a variable size (either __m128 or __m256) and isn't readily usable for interop scenarios
                // We can't block these types for field scenarios for back-compat reasons.

                if (type.HasInstantiation && !isField && (!isBlittable ||
                                                          InteropTypes.IsSystemByReference(context, type) ||
                                                          InteropTypes.IsSystemSpan(context, type) ||
                                                          InteropTypes.IsSystemReadOnlySpan(context, type) ||
                                                          InteropTypes.IsSystemNullable(context, type) ||
                                                          InteropTypes.IsSystemRuntimeIntrinsicsVector64T(context, type) ||
                                                          InteropTypes.IsSystemRuntimeIntrinsicsVector128T(context, type) ||
                                                          InteropTypes.IsSystemRuntimeIntrinsicsVector256T(context, type) ||
                                                          InteropTypes.IsSystemNumericsVectorT(context, type)))
                {
                    // Generic types cannot be marshaled.
                    return(MarshallerKind.Invalid);
                }

                if (isBlittable)
                {
                    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 READYTORUN
                // We don't want the additional test/maintenance cost of this in R2R.
                if (isByRef)
                {
                    return(MarshallerKind.Invalid);
                }
#else
                _ = isByRef;
#endif

                if (nativeType == NativeTypeKind.Default)
                {
                    nativeType = NativeTypeKind.Array;
                }

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

                    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)
            {
                if (nativeType == NativeTypeKind.Default)
                {
                    var pointedAtType = type.GetParameterType();
                    if (!pointedAtType.IsPrimitive && !type.IsEnum && marshallerType != MarshallerType.Field &&
                        HasCopyConstructorCustomModifier(parameterIndex, customModifierData))
                    {
                        return(MarshallerKind.BlittableValueClassWithCopyCtor);
                    }
                    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)
            {
                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.Default:
                    if (isAnsi)
                    {
                        return(MarshallerKind.AnsiString);
                    }
                    else
                    {
                        return(MarshallerKind.UnicodeString);
                    }

                default:
                    return(MarshallerKind.Invalid);
                }
            }
            else if (type.IsObject)
            {
                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);
                }
            }