/// <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 RegisterNativeInteropSignatures(CsCallable callable, bool isFunction) { var signatures = signatureTransform.GetInteropSignatures(callable, isFunction); foreach (var sig in signatures) { interopManager.Add(sig.Value); callable.InteropSignatures.Add(sig.Key, sig.Value); } }
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 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 void ProcessCallable(CsCallable csElement, bool isFunction) { try { var csMethod = csElement; Logger.PushContext("Method {0}", csMethod.CppElement); ProcessMethod(csMethod); RegisterNativeInteropSignatures(csMethod, isFunction); } finally { Logger.PopContext(); } }
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); }
/// <summary> /// Processes the specified method. /// </summary> /// <param name="method">The method.</param> private void ProcessMethod(CsCallable method) { var cppMethod = (CppCallable)method.CppElement; method.Name = NamingRules.Rename(cppMethod); // For methods, the tag "type" is only used for return type // So we are overriding the return type here var methodRule = cppMethod.GetMappingRule(); if (methodRule.MappingType != null) { cppMethod.ReturnValue.Rule = new MappingRule { MappingType = methodRule.MappingType } } ; // Get the inferred return type method.ReturnValue = factory.Create(cppMethod.ReturnValue); if (method.ReturnValue.PublicType is CsInterface iface && iface.IsCallback) { method.ReturnValue.PublicType = iface.GetNativeImplementationOrThis(); } // Hide return type only if it is a HRESULT and AlwaysReturnHResult is false if (method.CheckReturnType && method.ReturnValue.PublicType != null && method.ReturnValue.PublicType.QualifiedName == globalNamespace.GetTypeName(WellKnownName.Result)) { method.HideReturnType = !method.AlwaysReturnHResult; } // Iterates on parameters to convert them to C# parameters foreach (var cppParameter in cppMethod.Parameters) { var paramMethod = factory.Create(cppParameter); paramMethod.Name = NamingRules.Rename(cppParameter); method.Add(paramMethod); } }
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; }
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)); } }
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); }
public Dictionary <PlatformDetectionType, InteropMethodSignature> GetInteropSignatures(CsCallable callable, bool isFunction) { var interopSignatures = new Dictionary <PlatformDetectionType, InteropMethodSignature>(); if (callable.IsReturnStructLarge) { var sigWithRetBuf = GetNativeInteropSignatureWithForcedReturnBuffer(callable, isFunction); interopSignatures.Add(PlatformDetectionType.IsWindows, sigWithRetBuf); interopSignatures.Add(PlatformDetectionType.IsItaniumSystemV, GetNativeInteropSignature(callable, isFunction, PlatformDetectionType.IsItaniumSystemV)); } else { var returnType = callable.ReturnValue.PublicType.QualifiedName; InteropType windowsOverride; windowsOnlyReturnTypeOverrides.TryGetValue(returnType, out windowsOverride); InteropType systemvOverride; systemvOnlyReturnTypeOverrides.TryGetValue(returnType, out systemvOverride); if (windowsOverride == systemvOverride) { interopSignatures.Add(PlatformDetectionType.Any, GetNativeInteropSignature(callable, isFunction, PlatformDetectionType.Any)); } else { interopSignatures.Add(PlatformDetectionType.IsWindows, GetNativeInteropSignature(callable, isFunction, PlatformDetectionType.IsWindows)); interopSignatures.Add(PlatformDetectionType.IsItaniumSystemV, GetNativeInteropSignature(callable, isFunction, PlatformDetectionType.IsItaniumSystemV)); } } return(interopSignatures); }
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) { yield return(Argument(NativePointerIdentifierName), 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)); } }
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); }
public IDictionary <PlatformDetectionType, InteropMethodSignature> GetInteropSignatures(CsCallable callable) { var interopSignatures = new Dictionary <PlatformDetectionType, InteropMethodSignature>(); var isFunction = callable is CsFunction; // On Windows x86 and x64, if we have a native member function signature with a struct return type, we need to do a by-ref return. // see https://github.com/dotnet/runtime/issues/10901 // see https://github.com/dotnet/coreclr/pull/23145 if (callable.IsReturnStructLarge && !isFunction) { interopSignatures.Add( PlatformDetectionType.Windows, GetNativeInteropSignatureWithForcedReturnBuffer(callable, false) ); interopSignatures.Add( PlatformDetectionType.ItaniumSystemV, GetNativeInteropSignature(callable, false, PlatformDetectionType.ItaniumSystemV) ); } else { var returnType = callable.ReturnValue.PublicType.QualifiedName; windowsOnlyReturnTypeOverrides.TryGetValue(returnType, out var windowsOverride); systemvOnlyReturnTypeOverrides.TryGetValue(returnType, out var systemvOverride); if (windowsOverride == systemvOverride) { interopSignatures.Add(PlatformDetectionType.Any, GetNativeInteropSignature(callable, isFunction, PlatformDetectionType.Any)); } else { interopSignatures.Add(PlatformDetectionType.Windows, GetNativeInteropSignature(callable, isFunction, PlatformDetectionType.Windows)); interopSignatures.Add(PlatformDetectionType.ItaniumSystemV, GetNativeInteropSignature(callable, isFunction, PlatformDetectionType.ItaniumSystemV)); } } return(interopSignatures); }
internal static string GetMethodDelegateName(CsCallable csElement, PlatformDetectionType platform) => csElement.Name + "Delegate" + GeneratorHelpers.GetPlatformSpecificSuffix(platform);