Beispiel #1
0
        /// <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);
            }
        }
Beispiel #3
0
 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);
            }
        }
Beispiel #6
0
    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);
        }
Beispiel #15
0
        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
                       ));
        }
Beispiel #16
0
        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);