diff --git a/src/ObjCRuntime/Stret.cs b/src/ObjCRuntime/Stret.cs index 8f5a8aa67cd..d0352a1fd0c 100644 --- a/src/ObjCRuntime/Stret.cs +++ b/src/ObjCRuntime/Stret.cs @@ -155,7 +155,7 @@ public static bool ArmNeedStret (Type returnType, Generator generator) } #endif // BGENERATOR -#if BGENERATOR +#if BGENERATOR || RGEN public static bool X86NeedStret (Type returnType, Generator generator) { Type t = returnType; diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs index 59d8a127d50..32bc593c284 100644 --- a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs @@ -23,7 +23,7 @@ public static Dictionary> GetAttributeData (this ISy var boundAttributes = symbol.GetAttributes (); if (boundAttributes.Length == 0) { // return an empty dictionary if there are no attributes - return new (); + return new(); } var attributes = new Dictionary> (); @@ -102,7 +102,7 @@ public static bool HasAttribute (this ISymbol symbol, string attribute) if (attrName is null) return null; if (!attributes.TryGetValue (attrName, out var exportAttrDataList) || - exportAttrDataList.Count != 1) + exportAttrDataList.Count != 1) return null; var exportAttrData = exportAttrDataList [0]; @@ -115,7 +115,8 @@ public static bool HasAttribute (this ISymbol symbol, string attribute) return null; } - internal static T? GetAttribute (this ISymbol symbol, string attributeName, TryParse tryParse) where T : struct + internal static T? GetAttribute (this ISymbol symbol, string attributeName, TryParse tryParse) + where T : struct => GetAttribute (symbol, () => attributeName, tryParse); /// @@ -128,7 +129,7 @@ public static LayoutKind GetStructLayout (this ITypeSymbol symbol) // Check for StructLayout attribute with LayoutKind.Sequential var layoutAttribute = symbol.GetAttributes () .FirstOrDefault (attr => - attr.AttributeClass?.ToString () == typeof (StructLayoutAttribute).FullName); + attr.AttributeClass?.ToString () == typeof(StructLayoutAttribute).FullName); if (layoutAttribute is not null) { return (LayoutKind) layoutAttribute.ConstructorArguments [0].Value!; @@ -226,10 +227,11 @@ public static int GetFieldOffset (this IFieldSymbol symbol) { var offsetAttribute = symbol.GetAttributes () .FirstOrDefault (attr => - attr.AttributeClass?.ToString () == typeof (FieldOffsetAttribute).FullName); + attr.AttributeClass?.ToString () == typeof(FieldOffsetAttribute).FullName); return offsetAttribute is not null - ? (int) offsetAttribute.ConstructorArguments [0].Value! : 0; + ? (int) offsetAttribute.ConstructorArguments [0].Value! + : 0; } /// @@ -241,7 +243,7 @@ public static (UnmanagedType Type, int SizeConst)? GetMarshalAs (this ISymbol sy { var marshalAsAttribute = symbol.GetAttributes () .FirstOrDefault (attr => - attr.AttributeClass?.ToString () == typeof (MarshalAsAttribute).FullName); + attr.AttributeClass?.ToString () == typeof(MarshalAsAttribute).FullName); if (marshalAsAttribute is null) return null; var type = (UnmanagedType) marshalAsAttribute.ConstructorArguments [0].Value!; @@ -298,6 +300,9 @@ internal static bool TryGetBuiltInTypeSize (this ITypeSymbol symbol, bool is64bi return result; } + static bool TryGetBuiltInTypeSize (this ITypeSymbol type) + => TryGetBuiltInTypeSize (type, true /* doesn't matter */, out _); + static int AlignAndAdd (int size, int add, ref int maxElementSize) { maxElementSize = Math.Max (maxElementSize, add); @@ -307,7 +312,8 @@ static int AlignAndAdd (int size, int add, ref int maxElementSize) } - static void GetValueTypeSize (this ITypeSymbol originalSymbol, ITypeSymbol type, List fieldSymbols, bool is64Bits, ref int size, + static void GetValueTypeSize (this ITypeSymbol originalSymbol, ITypeSymbol type, List fieldSymbols, + bool is64Bits, ref int size, ref int maxElementSize) { // FIXME: @@ -328,13 +334,15 @@ static void GetValueTypeSize (this ITypeSymbol originalSymbol, ITypeSymbol type, GetValueTypeSize (originalSymbol, field.Type, fieldSymbols, is64Bits, ref size, ref maxElementSize); continue; } + var (marshalAsType, sizeConst) = marshalAs.Value; var multiplier = 1; switch (marshalAsType) { case UnmanagedType.ByValArray: var types = new List (); var arrayTypeSymbol = (field as IArrayTypeSymbol)!; - GetValueTypeSize (originalSymbol, arrayTypeSymbol.ElementType, types, is64Bits, ref typeSize, ref maxElementSize); + GetValueTypeSize (originalSymbol, arrayTypeSymbol.ElementType, types, is64Bits, ref typeSize, + ref maxElementSize); multiplier = sizeConst; break; case UnmanagedType.U1: @@ -356,13 +364,14 @@ static void GetValueTypeSize (this ITypeSymbol originalSymbol, ITypeSymbol type, typeSize = 8; break; default: - throw new Exception ($"Unhandled MarshalAs attribute: {marshalAs.Value} on field {field.ToDisplayString ()}"); + throw new Exception ( + $"Unhandled MarshalAs attribute: {marshalAs.Value} on field {field.ToDisplayString ()}"); } + fieldSymbols.Add (field.Type); size = AlignAndAdd (size, typeSize, ref maxElementSize); size += (multiplier - 1) * size; } - } /// @@ -436,5 +445,4 @@ public static void GetInheritance ( parents = parentsBuilder.ToImmutable (); interfaces = [.. interfacesSet]; } - } diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs index 70d64b65039..fd281dd5a31 100644 --- a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.Macios.Generator.Attributes; using Microsoft.Macios.Generator.Availability; @@ -149,4 +150,86 @@ public static BindingTypeData GetBindingData (this ISymbol symbol) where T /// returned. public static FieldData? GetFieldData (this ISymbol symbol) where T : Enum => GetAttribute> (symbol, AttributesNames.GetFieldAttributeName, FieldData.TryParse); + + public static bool X86NeedStret (ITypeSymbol returnType) + { + if (!returnType.IsValueType || returnType.SpecialType == SpecialType.System_Enum || + returnType.TryGetBuiltInTypeSize ()) + return false; + + var fieldTypes = new List (); + var size = GetValueTypeSize (returnType, fieldTypes, false); + + if (size > 8) + return true; + + return fieldTypes.Count == 3; + } + + public static bool X86_64NeedStret (ITypeSymbol returnType) + { + if (!returnType.IsValueType || returnType.SpecialType == SpecialType.System_Enum || + returnType.TryGetBuiltInTypeSize ()) + return false; + + var fieldTypes = new List (); + return GetValueTypeSize (returnType, fieldTypes, true) > 16; + } + + public static bool ArmNeedStret (ITypeSymbol returnType, Compilation compilation) + { + var currentPlatform = compilation.GetCurrentPlatform (); + bool has32bitArm = currentPlatform != PlatformName.TvOS && currentPlatform != PlatformName.MacOSX; + if (!has32bitArm) + return false; + + ITypeSymbol t = returnType; + + if (!t.IsValueType || t.SpecialType == SpecialType.System_Enum || t.TryGetBuiltInTypeSize()) + return false; + + var fieldTypes = new List (); + var size = t.GetValueTypeSize (fieldTypes, false); + + bool isiOS = currentPlatform == PlatformName.iOS; + + if (isiOS && size <= 4 && fieldTypes.Count == 1) { + +#pragma warning disable format + return fieldTypes [0] switch { + { Name: "nint" } => false, + { Name: "nuint" } => false, + { SpecialType: SpecialType.System_Char } => false, + { SpecialType: SpecialType.System_Byte } => false, + { SpecialType: SpecialType.System_SByte } => false, + { SpecialType: SpecialType.System_UInt16 } => false, + { SpecialType: SpecialType.System_Int16 } => false, + { SpecialType: SpecialType.System_UInt32 } => false, + { SpecialType: SpecialType.System_Int32 } => false, + { SpecialType: SpecialType.System_IntPtr } => false, + { SpecialType: SpecialType.System_UIntPtr } => false, + _ => true + }; +#pragma warning restore format + } + + return true; + } + + /// + /// Return if a given ITypeSymbol requires to use the objc_MsgSend_stret variants. + /// + /// The type we are testing. + /// The current compilation, used to determine the target platform. + /// If the type represented by the symtol needs a stret call variant. + public static bool NeedsStret (this ITypeSymbol returnType, Compilation compilation) + { + if (X86NeedStret (returnType)) + return true; + + if (X86_64NeedStret (returnType)) + return true; + + return ArmNeedStret (returnType, compilation); + } }