in src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs [215:671]
internal static MarshallerKind GetMarshallerKind(
TypeDesc type,
int? parameterIndex,
EmbeddedSignatureData[] customModifierData,
MarshalAsDescriptor marshalAs,
bool isReturn,
bool isAnsi,
MarshallerType marshallerType,
out MarshallerKind elementMarshallerKind)
{
elementMarshallerKind = MarshallerKind.Invalid;
TypeSystemContext context = type.Context;
NativeTypeKind nativeType = NativeTypeKind.Default;
bool isField = marshallerType == MarshallerType.Field;
if (marshalAs != null)
nativeType = marshalAs.Type;
bool isByRef = type.IsByRef;
if (isByRef)
{
type = type.GetParameterType();
if (type.IsValueType && !type.IsPrimitive && !type.IsEnum && !isField
&& HasCopyConstructorCustomModifier(parameterIndex, customModifierData))
{
return MarshallerKind.BlittableValueClassWithCopyCtor;
}
if (isReturn)
{
// Allow ref returning blittable structs for IJW
if (type.IsValueType &&
(nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default) &&
MarshalUtils.IsBlittableType(type))
{
return MarshallerKind.BlittableValueClassByRefReturn;
}
return MarshallerKind.Invalid;
}
}
if (nativeType == NativeTypeKind.CustomMarshaler)
{
if (isField)
return MarshallerKind.FailedTypeLoad;
else
return MarshallerKind.CustomMarshaler;
}
//
// Determine MarshalerKind
//
if (type.IsPrimitive)
{
switch (type.Category)
{
case TypeFlags.Void:
return MarshallerKind.VoidReturn;
case TypeFlags.Boolean:
switch (nativeType)
{
case NativeTypeKind.Default:
case NativeTypeKind.Boolean:
return MarshallerKind.Bool;
case NativeTypeKind.U1:
case NativeTypeKind.I1:
return MarshallerKind.CBool;
case NativeTypeKind.VariantBool:
if (context.Target.IsWindows)
return MarshallerKind.VariantBool;
else
return MarshallerKind.Invalid;
default:
return MarshallerKind.Invalid;
}
case TypeFlags.Char:
switch (nativeType)
{
case NativeTypeKind.I1:
case NativeTypeKind.U1:
return MarshallerKind.AnsiChar;
case NativeTypeKind.I2:
case NativeTypeKind.U2:
return MarshallerKind.UnicodeChar;
case NativeTypeKind.Default:
if (isAnsi)
return MarshallerKind.AnsiChar;
else
return MarshallerKind.UnicodeChar;
default:
return MarshallerKind.Invalid;
}
case TypeFlags.SByte:
case TypeFlags.Byte:
if (nativeType == NativeTypeKind.I1 || nativeType == NativeTypeKind.U1 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.Int16:
case TypeFlags.UInt16:
if (nativeType == NativeTypeKind.I2 || nativeType == NativeTypeKind.U2 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.Int32:
case TypeFlags.UInt32:
if (nativeType == NativeTypeKind.I4 || nativeType == NativeTypeKind.U4 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.Int64:
case TypeFlags.UInt64:
if (nativeType == NativeTypeKind.I8 || nativeType == NativeTypeKind.U8 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.IntPtr:
case TypeFlags.UIntPtr:
if (nativeType == NativeTypeKind.SysInt || nativeType == NativeTypeKind.SysUInt || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.Single:
if (nativeType == NativeTypeKind.R4 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.Double:
if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
default:
return MarshallerKind.Invalid;
}
}
else if (type.IsValueType)
{
if (type.IsEnum)
return MarshallerKind.Enum;
if (InteropTypes.IsSystemDateTime(context, type))
{
if (nativeType == NativeTypeKind.Default ||
nativeType == NativeTypeKind.Struct)
return MarshallerKind.OleDateTime;
else
return MarshallerKind.Invalid;
}
else if (InteropTypes.IsHandleRef(context, type))
{
if (nativeType == NativeTypeKind.Default)
return MarshallerKind.HandleRef;
else
return MarshallerKind.Invalid;
}
else if (InteropTypes.IsSystemDecimal(context, type))
{
if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default)
return MarshallerKind.Decimal;
else if (nativeType == NativeTypeKind.LPStruct && !isField)
return MarshallerKind.BlittableStructPtr;
else if (nativeType == NativeTypeKind.Currency)
return MarshallerKind.OleCurrency;
else
return MarshallerKind.Invalid;
}
else if (InteropTypes.IsSystemGuid(context, type))
{
if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableStruct;
else if (nativeType == NativeTypeKind.LPStruct && !isField)
return MarshallerKind.BlittableStructPtr;
else
return MarshallerKind.Invalid;
}
else if (InteropTypes.IsSystemArgIterator(context, type))
{
// Don't want to fall through to the blittable/haslayout case
return MarshallerKind.Invalid;
}
if (!IsValidForGenericMarshalling(type, isField))
{
// Generic types cannot be marshalled.
return MarshallerKind.Invalid;
}
if (!isField && ((DefType)type).IsInt128OrHasInt128Fields && !isByRef)
{
// Int128 types or structs that contain them cannot be passed by value
return MarshallerKind.Invalid;
}
if (!isField && ((DefType)type).IsVectorTOrHasVectorTFields)
{
// Vector<T> types or structs that contain them cannot be passed by value
return MarshallerKind.Invalid;
}
if (MarshalUtils.IsBlittableType(type))
{
if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct)
return MarshallerKind.Invalid;
return MarshallerKind.BlittableStruct;
}
else if (((MetadataType)type).HasLayout())
{
if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct)
return MarshallerKind.Invalid;
return MarshallerKind.Struct;
}
else
{
return MarshallerKind.Invalid;
}
}
else if (type.IsSzArray)
{
if (nativeType == NativeTypeKind.Default)
nativeType = NativeTypeKind.Array;
switch (nativeType)
{
case NativeTypeKind.Array:
{
if (isField)
return MarshallerKind.FailedTypeLoad;
var arrayType = (ArrayType)type;
elementMarshallerKind = GetArrayElementMarshallerKind(
arrayType,
marshalAs,
isAnsi);
// If element is invalid type, the array itself is invalid
if (elementMarshallerKind == MarshallerKind.Invalid)
return MarshallerKind.Invalid;
if (elementMarshallerKind == MarshallerKind.AnsiChar)
return MarshallerKind.AnsiCharArray;
else if (elementMarshallerKind == MarshallerKind.UnicodeChar // Arrays of unicode char should be marshalled as blittable arrays
|| elementMarshallerKind == MarshallerKind.Enum
|| elementMarshallerKind == MarshallerKind.BlittableValue)
return MarshallerKind.BlittableArray;
else
return MarshallerKind.Array;
}
case NativeTypeKind.ByValArray: // fix sized array
{
var arrayType = (ArrayType)type;
elementMarshallerKind = GetArrayElementMarshallerKind(
arrayType,
marshalAs,
isAnsi);
// If element is invalid type, the array itself is invalid
if (elementMarshallerKind == MarshallerKind.Invalid)
return MarshallerKind.Invalid;
if (elementMarshallerKind == MarshallerKind.AnsiChar)
return MarshallerKind.ByValAnsiCharArray;
else
return MarshallerKind.ByValArray;
}
default:
return MarshallerKind.Invalid;
}
}
else if (type.IsPointer)
{
type = type.GetParameterType();
if (type.IsValueType && !type.IsPrimitive && !type.IsEnum && !isField
&& HasCopyConstructorCustomModifier(parameterIndex, customModifierData))
{
return MarshallerKind.BlittableValueClassWithCopyCtor;
}
if (nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
}
else if (type.IsFunctionPointer)
{
if (nativeType == NativeTypeKind.Func || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
}
else if (type.IsDelegate || InteropTypes.IsSystemDelegate(context, type) || InteropTypes.IsSystemMulticastDelegate(context, type))
{
if (type.HasInstantiation)
{
// Generic types cannot be marshaled.
return MarshallerKind.Invalid;
}
if (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Func)
return MarshallerKind.FunctionPointer;
else
return MarshallerKind.Invalid;
}
else if (type.IsString)
{
switch (nativeType)
{
case NativeTypeKind.LPWStr:
return MarshallerKind.UnicodeString;
case NativeTypeKind.LPStr:
return MarshallerKind.AnsiString;
case NativeTypeKind.LPUTF8Str:
return MarshallerKind.UTF8String;
case NativeTypeKind.LPTStr:
return MarshallerKind.UnicodeString;
case NativeTypeKind.ByValTStr:
if (isAnsi)
{
elementMarshallerKind = MarshallerKind.AnsiChar;
return MarshallerKind.ByValAnsiString;
}
else
{
elementMarshallerKind = MarshallerKind.UnicodeChar;
return MarshallerKind.ByValUnicodeString;
}
case NativeTypeKind.TBStr:
case NativeTypeKind.BStr:
return MarshallerKind.BSTRString;
case NativeTypeKind.AnsiBStr:
return MarshallerKind.AnsiBSTRString;
case NativeTypeKind.CustomMarshaler:
return MarshallerKind.CustomMarshaler;
case NativeTypeKind.Default:
if (isAnsi)
return MarshallerKind.AnsiString;
else
return MarshallerKind.UnicodeString;
default:
return MarshallerKind.Invalid;
}
}
else if (type.IsObject)
{
if (nativeType == NativeTypeKind.AsAny && isField)
return MarshallerKind.FailedTypeLoad;
if (nativeType == NativeTypeKind.AsAny)
return isAnsi ? MarshallerKind.AsAnyA : MarshallerKind.AsAnyW;
else
if (context.Target.IsWindows)
{
if ((isField && nativeType == NativeTypeKind.Default)
|| nativeType == NativeTypeKind.Intf
|| nativeType == NativeTypeKind.IUnknown)
return MarshallerKind.ComInterface;
else
return MarshallerKind.Variant;
}
else
return MarshallerKind.Invalid;
}
else if (InteropTypes.IsStringBuilder(context, type))
{
switch (nativeType)
{
case NativeTypeKind.Default:
if (isAnsi)
{
return MarshallerKind.AnsiStringBuilder;
}
else
{
return MarshallerKind.UnicodeStringBuilder;
}
case NativeTypeKind.LPStr:
return MarshallerKind.AnsiStringBuilder;
case NativeTypeKind.LPWStr:
return MarshallerKind.UnicodeStringBuilder;
default:
return MarshallerKind.Invalid;
}
}
else if (InteropTypes.IsSafeHandle(context, type))
{
if (nativeType == NativeTypeKind.Default)
return MarshallerKind.SafeHandle;
else
return MarshallerKind.Invalid;
}
else if (InteropTypes.IsCriticalHandle(context, type))
{
if (nativeType == NativeTypeKind.Default)
return MarshallerKind.CriticalHandle;
else
return MarshallerKind.Invalid;
}
else if (type is MetadataType mdType && mdType.HasLayout())
{
if (type.HasInstantiation)
{
// Generic types cannot be marshaled.
return MarshallerKind.Invalid;
}
if (!isField && nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.LPStruct)
return MarshallerKind.LayoutClassPtr;
else if (isField && (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Struct))
return MarshallerKind.LayoutClass;
else
return MarshallerKind.Invalid;
}
else if (type.IsInterface)
{
if (context.Target.IsWindows)
return MarshallerKind.ComInterface;
else
return MarshallerKind.Invalid;
}
else
{
return MarshallerKind.Invalid;
}
}