/// <summary> /// Registers the native interop signature. /// </summary> /// <param name="callable">The cs method.</param> private void RegisterNativeInteropSignature(CsCallable callable, bool isFunction) { // Tag if the method is a function var cSharpInteropCalliSignature = new InteropMethodSignature { IsFunction = isFunction, CallingConvention = callable.CallingConvention }; InitSignatureWithReturnType(callable, cSharpInteropCalliSignature); // Handle Parameters foreach (var param in callable.Parameters) { var(interopType, isLocal) = GetInteropTypeForParameter(param); if (interopType == null) { Logger.Error(LoggingCodes.InvalidMethodParameterType, "Invalid parameter {0} for method {1}", param.PublicType.QualifiedName, callable.CppElement); } cSharpInteropCalliSignature.IsLocal |= isLocal; cSharpInteropCalliSignature.ParameterTypes.Add(interopType); } var assembly = callable.GetParent <CsAssembly>(); cSharpInteropCalliSignature = assembly.Interop.Add(cSharpInteropCalliSignature); callable.Interop = cSharpInteropCalliSignature; }
private void InitSignatureWithReturnType(CsCallable callable, InteropMethodSignature cSharpInteropCalliSignature) { // Handle Return Type parameter // MarshalType.Type == null, then check that it is a structure if (callable.ReturnValue.PublicType is CsStruct || callable.ReturnValue.PublicType is CsEnum) { // Return type and 1st parameter are implicitly a pointer to the structure to fill if (callable.IsReturnStructLarge) { cSharpInteropCalliSignature.ReturnType = typeof(void *); cSharpInteropCalliSignature.ParameterTypes.Add(typeof(void *)); } else { var returnQualifiedName = callable.ReturnValue.PublicType.QualifiedName; if (returnQualifiedName == globalNamespace.GetTypeName(WellKnownName.Result)) { cSharpInteropCalliSignature.ReturnType = typeof(int); } else if (returnQualifiedName == globalNamespace.GetTypeName(WellKnownName.PointerSize)) { cSharpInteropCalliSignature.ReturnType = typeof(void *); } else if (callable.ReturnValue.HasNativeValueType) { cSharpInteropCalliSignature.ReturnType = $"{callable.ReturnValue.MarshalType.QualifiedName}.__Native"; } else { cSharpInteropCalliSignature.ReturnType = callable.ReturnValue.MarshalType.QualifiedName; } } } else if (callable.ReturnValue.MarshalType is CsFundamentalType fundamentalReturn) { cSharpInteropCalliSignature.ReturnType = fundamentalReturn.Type; } else if (callable.ReturnValue.HasPointer) { if (callable.ReturnValue.IsInterface) { cSharpInteropCalliSignature.ReturnType = typeof(IntPtr); } else { cSharpInteropCalliSignature.ReturnType = typeof(void *); } } else { Logger.Error(LoggingCodes.InvalidMethodReturnType, "Invalid return type {0} for method {1}", callable.ReturnValue.PublicType.QualifiedName, callable.CppElement); } }
private void InitSignatureWithReturnType(CsCallable callable, InteropMethodSignature cSharpInteropCalliSignature, PlatformDetectionType platform) { Debug.Assert((platform & (PlatformDetectionType.IsWindows | PlatformDetectionType.IsItaniumSystemV)) != (PlatformDetectionType.IsWindows | PlatformDetectionType.IsItaniumSystemV) || !callable.IsReturnStructLarge); var platformSpecificReturnTypeOverrides = (platform & PlatformDetectionType.IsWindows) != 0 ? windowsOnlyReturnTypeOverrides : systemvOnlyReturnTypeOverrides; // Handle Return Type parameter // MarshalType.Type == null, then check that it is a structure if (callable.ReturnValue.PublicType is CsStruct || callable.ReturnValue.PublicType is CsEnum) { var returnQualifiedName = callable.ReturnValue.PublicType.QualifiedName; if (returnTypeOverrides.TryGetValue(returnQualifiedName, out var interopType)) { cSharpInteropCalliSignature.ReturnType = interopType.NewType; cSharpInteropCalliSignature.Flags |= interopType.SetFlags; } else if (platformSpecificReturnTypeOverrides.TryGetValue(returnQualifiedName, out interopType)) { cSharpInteropCalliSignature.ReturnType = interopType.NewType; cSharpInteropCalliSignature.Flags |= interopType.SetFlags; } else if (callable.ReturnValue.HasNativeValueType) { cSharpInteropCalliSignature.ReturnType = $"{callable.ReturnValue.MarshalType.QualifiedName}.__Native"; } else { cSharpInteropCalliSignature.ReturnType = callable.ReturnValue.MarshalType.QualifiedName; } } else if (callable.ReturnValue.MarshalType is CsFundamentalType fundamentalReturn) { cSharpInteropCalliSignature.ReturnType = fundamentalReturn.Type; } else if (callable.ReturnValue.HasPointer) { if (callable.ReturnValue.IsInterface) { cSharpInteropCalliSignature.ReturnType = typeof(IntPtr); } else { cSharpInteropCalliSignature.ReturnType = typeof(void *); } } else { cSharpInteropCalliSignature.ReturnType = callable.ReturnValue.PublicType.QualifiedName; logger.Error(LoggingCodes.InvalidMethodReturnType, "Invalid return type {0} for method {1}", callable.ReturnValue.PublicType.QualifiedName, callable.CppElement); } }
private void InitCalliSignatureParameters(CsCallable callable, InteropMethodSignature cSharpInteropCalliSignature) { foreach (var param in callable.Parameters) { var interopType = GetInteropTypeForParameter(param); if (interopType == null) { logger.Error(LoggingCodes.InvalidMethodParameterType, "Invalid parameter {0} for method {1}", param.PublicType.QualifiedName, callable.CppElement); } cSharpInteropCalliSignature.ParameterTypes.Add(interopType); } }
private InteropMethodSignature GetNativeInteropSignatureWithForcedReturnBuffer(CsCallable callable, bool isFunction) { var cSharpInteropCalliSignature = new InteropMethodSignature { IsFunction = isFunction, CallingConvention = callable.CallingConvention, ForcedReturnBufferSig = true, ReturnType = typeof(void *), ParameterTypes = { typeof(void *) } }; InitCalliSignatureParameters(callable, cSharpInteropCalliSignature); return(cSharpInteropCalliSignature); }
private void InitSignatureWithReturnType(CsCallable callable, InteropMethodSignature cSharpInteropCalliSignature, PlatformDetectionType platform) { var returnType = CoerceToBlittable(GetInteropTypeForReturnValue(callable.ReturnValue, platform)); if (returnType is null) { Logger.Error(LoggingCodes.InvalidMethodReturnType, "Invalid return type {0} for method {1}", callable.ReturnValue.PublicType.QualifiedName, callable.CppElement); returnType = callable.ReturnValue.PublicType.QualifiedName; } cSharpInteropCalliSignature.ReturnType = returnType; }
/// <summary> /// Registers the native interop signature. /// </summary> /// <param name="callable">The cs method.</param> private InteropMethodSignature GetNativeInteropSignature(CsCallable callable, bool isFunction, PlatformDetectionType platform) { // Tag if the method is a function var cSharpInteropCalliSignature = new InteropMethodSignature { IsFunction = isFunction, CallingConvention = callable.CallingConvention }; InitSignatureWithReturnType(callable, cSharpInteropCalliSignature, platform); // Handle Parameters InitCalliSignatureParameters(callable, cSharpInteropCalliSignature); return(cSharpInteropCalliSignature); }
private InteropMethodSignature GetNativeInteropSignatureWithForcedReturnBuffer(CsCallable callable, bool isFunction) { var cSharpInteropCalliSignature = new InteropMethodSignature { IsFunction = isFunction, CallingConvention = callable.CallingConvention, Flags = InteropMethodSignatureFlags.ForcedReturnBufferSig }; cSharpInteropCalliSignature.ReturnType = typeof(void *); cSharpInteropCalliSignature.ParameterTypes.Add(typeof(void *)); InitCalliSignatureParameters(callable, cSharpInteropCalliSignature); return(cSharpInteropCalliSignature); }
private InteropMethodSignature GetNativeInteropSignatureWithForcedReturnBuffer( CsCallable callable, bool isFunction) { var cSharpInteropCalliSignature = new InteropMethodSignature { IsFunction = isFunction, CallingConvention = callable.CppCallingConvention, ForcedReturnBufferSig = true, ReturnType = TypeRegistry.VoidPtr, ParameterTypes = { new InteropMethodSignatureParameter(TypeRegistry.VoidPtr, callable.ReturnValue, "returnSlot") } }; InitCalliSignatureParameters(callable, cSharpInteropCalliSignature); return(cSharpInteropCalliSignature); }
private void InitSignatureWithReturnType(CsCallable callable, InteropMethodSignature cSharpInteropCalliSignature, PlatformDetectionType platform) { InteropMethodSignatureFlags flags = default; var returnType = GetInteropTypeForReturnValue(callable.ReturnValue, platform, ref flags); if (returnType == null) { logger.Error(LoggingCodes.InvalidMethodReturnType, "Invalid return type {0} for method {1}", callable.ReturnValue.PublicType.QualifiedName, callable.CppElement); returnType = callable.ReturnValue.PublicType.QualifiedName; } if (flags != default) { cSharpInteropCalliSignature.Flags |= flags; } cSharpInteropCalliSignature.ReturnType = returnType; }
/// <summary> /// Registers the native interop signature. /// </summary> /// <param name="csMethod">The cs method.</param> private void RegisterNativeInteropSignature(CsMethod csMethod) { // Tag if the method is a function var cSharpInteropCalliSignature = new InteropMethodSignature { IsFunction = (csMethod is CsFunction) }; // Handle Return Type parameter // MarshalType.Type == null, then check that it is a structure if (csMethod.ReturnType.PublicType is CsStruct || csMethod.ReturnType.PublicType is CsEnum) { // Return type and 1st parameter are implicitly a pointer to the structure to fill if (csMethod.IsReturnStructLarge) { cSharpInteropCalliSignature.ReturnType = typeof(void *); cSharpInteropCalliSignature.ParameterTypes.Add(typeof(void *)); } else { // Patch for Mono bug with structs marshalling and calli. var returnQualifiedName = csMethod.ReturnType.PublicType.QualifiedName; if (returnQualifiedName == Manager.GlobalNamespace.GetTypeName("Result")) { cSharpInteropCalliSignature.ReturnType = typeof(int); } else if (returnQualifiedName == Manager.GlobalNamespace.GetTypeName("PointerSize")) { cSharpInteropCalliSignature.ReturnType = typeof(void *); } else { cSharpInteropCalliSignature.ReturnType = csMethod.ReturnType.PublicType.QualifiedName; } } } else if (csMethod.ReturnType.MarshalType.Type != null) { Type type = csMethod.ReturnType.MarshalType.Type; cSharpInteropCalliSignature.ReturnType = type; } else { throw new ArgumentException(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Invalid return type {0} for method {1}", csMethod.ReturnType.PublicType.QualifiedName, csMethod.CppElement)); } // Handle Parameters foreach (var param in csMethod.Parameters) { InteropType interopType; string publicName = param.PublicType.QualifiedName; // Patch for Mono bug with structs marshalling and calli. if (publicName == Manager.GlobalNamespace.GetTypeName("PointerSize")) { interopType = typeof(void *); } else if (param.MarshalType.Type == null) { if (param.PublicType is CsStruct) { // If parameter is a struct, then a LocalInterop is needed interopType = param.PublicType.QualifiedName; cSharpInteropCalliSignature.IsLocal = true; } else { throw new ArgumentException(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Invalid parameter {0} for method {1}", param.PublicType.QualifiedName, csMethod.CppElement)); } } else { Type type = param.MarshalType.Type; // Patch for Mono bug with structs marshalling and calli. if (type == typeof(IntPtr)) { type = typeof(void *); } interopType = type; } cSharpInteropCalliSignature.ParameterTypes.Add(interopType); } var assembly = csMethod.GetParent <CsAssembly>(); cSharpInteropCalliSignature = assembly.Interop.Add(cSharpInteropCalliSignature); csMethod.Interop = cSharpInteropCalliSignature; }
private DelegateDeclarationSyntax GenerateDelegateDeclaration(CsCallable csElement, PlatformDetectionType platform, InteropMethodSignature sig) { return(DelegateDeclaration(ParseTypeName(sig.ReturnType.TypeName), VtblGenerator.GetMethodDelegateName(csElement, platform)) .AddAttributeLists( AttributeList( SingletonSeparatedList( Attribute( ParseName("System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute")) .AddArgumentListArguments( AttributeArgument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("System"), IdentifierName("Runtime")), IdentifierName("InteropServices")), IdentifierName("CallingConvention")), IdentifierName(sig.CallingConvention.ToManagedCallingConventionName()))))))) .WithParameterList( ParameterList( (csElement is CsMethod ? SingletonSeparatedList( Parameter(Identifier("thisObject")) .WithType(ParseTypeName("System.IntPtr"))) : default)
private IEnumerable <(ArgumentSyntax Argument, TypeSyntax Type)> IterateNativeArguments(bool isMethod, InteropMethodSignature interopSig) { if (isMethod) { yield return(NativePointerArgument, GeneratorHelpers.IntPtrType); } (ArgumentSyntax, TypeSyntax) ParameterSelector(InteropMethodSignatureParameter param) { var csElement = param.Item; return(GetMarshaller(csElement).GenerateNativeArgument(csElement), param.InteropTypeSyntax); } foreach (var parameter in interopSig.ParameterTypes) { yield return(ParameterSelector(parameter)); } }
public ExpressionSyntax GenerateCall(CsCallable callable, PlatformDetectionType platform, InteropMethodSignature interopSig) { var arguments = IterateNativeArguments(callable, interopSig).ToArray(); ElementAccessExpressionSyntax vtblAccess = null; if (callable is CsMethod method) { var windowsOffsetExpression = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(method.WindowsOffset)); var nonWindowsOffsetExpression = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(method.Offset)); ExpressionSyntax vtableOffsetExpression; if ((platform & PlatformDetectionType.Any) == PlatformDetectionType.Any && method.Offset != method.WindowsOffset) { vtableOffsetExpression = ConditionalExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, GlobalNamespace.GetTypeNameSyntax(WellKnownName.PlatformDetection), IdentifierName("Is" + nameof(PlatformDetectionType.Windows))), windowsOffsetExpression, nonWindowsOffsetExpression); } else if ((platform & PlatformDetectionType.Windows) != 0) { vtableOffsetExpression = windowsOffsetExpression; } else { vtableOffsetExpression = nonWindowsOffsetExpression; } vtblAccess = ElementAccessExpression( ThisExpression(), BracketedArgumentList( SingletonSeparatedList( Argument( method.CustomVtbl ? MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName($"{callable.Name}__vtbl_index") ) : vtableOffsetExpression ) ) ) ); } ExpressionSyntax FnPtrCall() { var fnptrParameters = arguments .Select(x => x.Type) .Append(ParseTypeName(interopSig.ReturnType.TypeName)) .Select(FunctionPointerParameter); return(GeneratorHelpers.CastExpression( FunctionPointerType( FunctionPointerCallingConvention( Token(SyntaxKind.UnmanagedKeyword), FunctionPointerUnmanagedCallingConventionList( SingletonSeparatedList( FunctionPointerUnmanagedCallingConvention( Identifier(callable.CppCallingConvention.ToCallConvShortName()) ) ) ) ), FunctionPointerParameterList(SeparatedList(fnptrParameters)) ), vtblAccess )); } var what = callable switch { CsFunction => IdentifierName( callable.CppElementName + GeneratorHelpers.GetPlatformSpecificSuffix(platform) ), CsMethod => GeneratorHelpers.WrapInParentheses(FnPtrCall()), _ => throw new ArgumentOutOfRangeException() }; ExpressionSyntax call = InvocationExpression( what, ArgumentList(SeparatedList(arguments.Select(x => x.Argument))) ); if (interopSig.CastToNativeLong) { call = CastExpression(GlobalNamespace.GetTypeNameSyntax(WellKnownName.NativeLong), call); } if (interopSig.CastToNativeULong) { call = CastExpression(GlobalNamespace.GetTypeNameSyntax(WellKnownName.NativeULong), call); } if (interopSig.ForcedReturnBufferSig || !callable.HasReturnType) { return(call); } return(AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, GetMarshaller(callable.ReturnValue).GeneratesMarshalVariable(callable.ReturnValue) ? MarshallerBase.GetMarshalStorageLocation(callable.ReturnValue) : IdentifierName(callable.ReturnValue.Name), call )); }
private IEnumerable <(ArgumentSyntax Argument, TypeSyntax Type)> IterateNativeArguments(CsCallable callable, InteropMethodSignature interopSig) { if (callable is CsMethod) { var ptr = MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName("_nativePointer") ); yield return(Argument(ptr), VoidPtr); } (ArgumentSyntax, TypeSyntax) ParameterSelector(InteropMethodSignatureParameter param) { var csElement = param.Item; var marshaller = generators.Marshalling.GetMarshaller(csElement); return(marshaller.GenerateNativeArgument(csElement), param.InteropTypeSyntax); } foreach (var parameter in interopSig.ParameterTypes) { yield return(ParameterSelector(parameter)); } }