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