From f0c14473485163735be49867c7cde85f7dc4c446 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 17 Mar 2022 12:28:59 -0700 Subject: [PATCH 1/2] Replace AsArgument/AsParameter with enum-based options to help simplify future work with non-forward-P/Invoke support (in particular unmanaged->managed support). This change will enable us to add behavior in one place to support getting the native value from the argument so we don't need to manually add identical (or nearly identical) behavior to every one of our marshalling generators. --- .../PInvokeStubCodeGenerator.cs | 6 +- .../Marshalling/ArrayMarshaller.cs | 11 +- .../Marshalling/BlittableMarshaller.cs | 19 +- .../Marshalling/BoolMarshaller.cs | 18 +- .../Marshalling/CharMarshaller.cs | 39 ++-- ...nditionalStackallocMarshallingGenerator.cs | 4 +- .../CustomNativeTypeMarshallingGenerator.cs | 12 +- .../Marshalling/DelegateMarshaller.cs | 21 +- .../Marshalling/Forwarder.cs | 134 +----------- .../ICustomNativeTypeMarshallingStrategy.cs | 60 ------ .../MarshalAsMarshallingGeneratorFactory.cs | 2 +- .../Marshalling/MarshallingGenerator.cs | 59 ++++-- .../MarshallingGeneratorExtensions.cs | 194 ++++++++++++++++++ .../PinnableManagedValueMarshaller.cs | 40 ++-- .../Marshalling/SafeHandleMarshaller.cs | 21 +- .../Marshalling/StringMarshaller.Ansi.cs | 30 +-- .../Marshalling/StringMarshaller.Utf16.cs | 60 +----- .../Marshalling/StringMarshaller.Utf8.cs | 25 +-- 18 files changed, 333 insertions(+), 422 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs index 65920dc750d820..fc0baa4b2d0dda 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs @@ -512,10 +512,8 @@ void GenerateStatementsForInvoke(List statementsToUpdate, Invoc ParameterList( SeparatedList( _paramMarshallers.Select(marshaler => marshaler.Generator.AsParameter(marshaler.TypeInfo)))), - _retMarshaller.Generator.AsNativeType(_retMarshaller.TypeInfo), - _retMarshaller.Generator is IAttributedReturnTypeMarshallingGenerator attributedReturn - ? attributedReturn.GenerateAttributesForReturnType(_retMarshaller.TypeInfo) - : null + _retMarshaller.Generator.AsReturnType(_retMarshaller.TypeInfo), + _retMarshaller.Generator.GenerateAttributesForReturnType(_retMarshaller.TypeInfo) ); } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs index 450ba62c1aaa1c..df914b3b3cfc18 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs @@ -27,14 +27,13 @@ public bool IsSupported(TargetFramework target, Version version) return target is TargetFramework.Net && version.Major >= 7; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { if (IsPinningPathSupported(info, context)) { - string identifier = context.GetIdentifiers(info).native; - return Argument(CastExpression(AsNativeType(info), IdentifierName(identifier))); + return ValueBoundaryBehavior.NativeIdentifier; } - return _manualMarshallingGenerator.AsArgument(info, context); + return _manualMarshallingGenerator.GetValueBoundaryBehavior(info, context); } public TypeSyntax AsNativeType(TypePositionInfo info) @@ -42,9 +41,9 @@ public TypeSyntax AsNativeType(TypePositionInfo info) return _manualMarshallingGenerator.AsNativeType(info); } - public ParameterSyntax AsParameter(TypePositionInfo info) + public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - return _manualMarshallingGenerator.AsParameter(info); + return _manualMarshallingGenerator.GetNativeSignatureBehavior(info); } public IEnumerable Generate(TypePositionInfo info, StubCodeContext context) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs index b137316d21aedb..bc2de37e5b5486 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs @@ -20,29 +20,22 @@ public TypeSyntax AsNativeType(TypePositionInfo info) return info.ManagedType.Syntax; } - public ParameterSyntax AsParameter(TypePositionInfo info) + public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - TypeSyntax type = info.IsByRef - ? PointerType(AsNativeType(info)) - : AsNativeType(info); - return Parameter(Identifier(info.InstanceIdentifier)) - .WithType(type); + return info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { if (!info.IsByRef) { - return Argument(IdentifierName(info.InstanceIdentifier)); + return ValueBoundaryBehavior.ManagedIdentifier; } else if (context.SingleFrameSpansNativeContext && !info.IsManagedReturnPosition) { - return Argument(IdentifierName(context.GetIdentifiers(info).native)); + return ValueBoundaryBehavior.NativeIdentifier; } - return Argument( - PrefixUnaryExpression( - SyntaxKind.AddressOfExpression, - IdentifierName(context.GetIdentifiers(info).native))); + return ValueBoundaryBehavior.AddressOfNativeIdentifier; } public IEnumerable Generate(TypePositionInfo info, StubCodeContext context) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs index 247d19ff1cf2c0..7ad4c7c58b887f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs @@ -35,27 +35,19 @@ public TypeSyntax AsNativeType(TypePositionInfo info) return _nativeType; } - public ParameterSyntax AsParameter(TypePositionInfo info) + public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - TypeSyntax type = info.IsByRef - ? PointerType(AsNativeType(info)) - : AsNativeType(info); - return Parameter(Identifier(info.InstanceIdentifier)) - .WithType(type); + return info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { - string identifier = context.GetIdentifiers(info).native; if (info.IsByRef) { - return Argument( - PrefixUnaryExpression( - SyntaxKind.AddressOfExpression, - IdentifierName(identifier))); + return ValueBoundaryBehavior.AddressOfNativeIdentifier; } - return Argument(IdentifierName(identifier)); + return ValueBoundaryBehavior.NativeIdentifier; } public IEnumerable Generate(TypePositionInfo info, StubCodeContext context) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs index 293b97959d63b1..0421c1d6da557a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs @@ -22,31 +22,18 @@ public Utf16CharMarshaller() public bool IsSupported(TargetFramework target, Version version) => true; - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { - (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); if (!info.IsByRef) { - // (ushort) - return Argument( - CastExpression( - AsNativeType(info), - IdentifierName(managedIdentifier))); + return ValueBoundaryBehavior.ManagedIdentifier; } else if (IsPinningPathSupported(info, context)) { - // (ushort*) - return Argument( - CastExpression( - PointerType(AsNativeType(info)), - IdentifierName(PinnedIdentifier(info.InstanceIdentifier)))); + return ValueBoundaryBehavior.NativeIdentifier; } - // & - return Argument( - PrefixUnaryExpression( - SyntaxKind.AddressOfExpression, - IdentifierName(nativeIdentifier))); + return ValueBoundaryBehavior.AddressOfNativeIdentifier; } public TypeSyntax AsNativeType(TypePositionInfo info) @@ -55,13 +42,9 @@ public TypeSyntax AsNativeType(TypePositionInfo info) return s_nativeType; } - public ParameterSyntax AsParameter(TypePositionInfo info) + public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - TypeSyntax type = info.IsByRef - ? PointerType(AsNativeType(info)) - : AsNativeType(info); - return Parameter(Identifier(info.InstanceIdentifier)) - .WithType(type); + return info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType; } public IEnumerable Generate(TypePositionInfo info, StubCodeContext context) @@ -85,7 +68,15 @@ public IEnumerable Generate(TypePositionInfo info, StubCodeCont )) ) ), - EmptyStatement() + // ushort* = (ushort*); + LocalDeclarationStatement( + VariableDeclaration(PointerType(AsNativeType(info)), + SingletonSeparatedList( + VariableDeclarator(nativeIdentifier) + .WithInitializer(EqualsValueClause( + CastExpression( + PointerType(AsNativeType(info)), + IdentifierName(PinnedIdentifier(info.InstanceIdentifier)))))))) ); } yield break; diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs index fb097a53a12f50..970e8da3d22166 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs @@ -238,10 +238,10 @@ public virtual bool IsSupported(TargetFramework target, Version version) public abstract TypeSyntax AsNativeType(TypePositionInfo info); /// - public abstract ParameterSyntax AsParameter(TypePositionInfo info); + public abstract SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info); /// - public abstract ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context); + public abstract ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context); /// public abstract IEnumerable Generate(TypePositionInfo info, StubCodeContext context); diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs index 4a27fa3cb4eb56..c770312495087c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs @@ -28,9 +28,9 @@ public bool IsSupported(TargetFramework target, Version version) return target is TargetFramework.Net && version.Major >= 6; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { - return _nativeTypeMarshaller.AsArgument(info, context); + return info.IsByRef ? ValueBoundaryBehavior.AddressOfNativeIdentifier : ValueBoundaryBehavior.NativeIdentifier; } public TypeSyntax AsNativeType(TypePositionInfo info) @@ -38,13 +38,9 @@ public TypeSyntax AsNativeType(TypePositionInfo info) return _nativeTypeMarshaller.AsNativeType(info); } - public ParameterSyntax AsParameter(TypePositionInfo info) + public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - TypeSyntax type = info.IsByRef - ? PointerType(AsNativeType(info)) - : AsNativeType(info); - return Parameter(Identifier(info.InstanceIdentifier)) - .WithType(type); + return info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType; } public IEnumerable Generate(TypePositionInfo info, StubCodeContext context) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs index 4db41933d591a5..ff9873c93b3b9e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs @@ -19,27 +19,14 @@ public TypeSyntax AsNativeType(TypePositionInfo info) return MarshallerHelpers.SystemIntPtrType; } - public ParameterSyntax AsParameter(TypePositionInfo info) + public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - TypeSyntax type = info.IsByRef - ? PointerType(AsNativeType(info)) - : AsNativeType(info); - return Parameter(Identifier(info.InstanceIdentifier)) - .WithType(type); + return info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { - string identifier = context.GetIdentifiers(info).native; - if (info.IsByRef) - { - return Argument( - PrefixUnaryExpression( - SyntaxKind.AddressOfExpression, - IdentifierName(identifier))); - } - - return Argument(IdentifierName(identifier)); + return info.IsByRef ? ValueBoundaryBehavior.AddressOfNativeIdentifier : ValueBoundaryBehavior.NativeIdentifier; } public IEnumerable Generate(TypePositionInfo info, StubCodeContext context) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs index 92533d720031e9..561673d501318c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs @@ -11,7 +11,7 @@ namespace Microsoft.Interop { - public sealed class Forwarder : IMarshallingGenerator, IAttributedReturnTypeMarshallingGenerator + public sealed class Forwarder : IMarshallingGenerator { public bool IsSupported(TargetFramework target, Version version) => true; @@ -20,129 +20,14 @@ public TypeSyntax AsNativeType(TypePositionInfo info) return info.ManagedType.Syntax; } - private bool TryRehydrateMarshalAsAttribute(TypePositionInfo info, out AttributeSyntax marshalAsAttribute) + public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - marshalAsAttribute = null!; - // If the parameter has [MarshalAs] marshalling, we resurface that - // in the forwarding target since the built-in system understands it. - // ICustomMarshaller marshalling requires additional information that we throw away earlier since it's unsupported, - // so explicitly do not resurface a [MarshalAs(UnmanagdType.CustomMarshaler)] attribute. - if (info.MarshallingAttributeInfo is MarshalAsInfo { UnmanagedType: not UnmanagedType.CustomMarshaler } marshalAs) - { - marshalAsAttribute = Attribute(ParseName(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)) - .WithArgumentList(AttributeArgumentList(SingletonSeparatedList(AttributeArgument( - CastExpression(ParseTypeName(TypeNames.System_Runtime_InteropServices_UnmanagedType), - LiteralExpression(SyntaxKind.NumericLiteralExpression, - Literal((int)marshalAs.UnmanagedType))))))); - return true; - } - - if (info.ManagedType is SzArrayType) - { - CountInfo countInfo; - MarshallingInfo elementMarshallingInfo; - if (info.MarshallingAttributeInfo is NativeContiguousCollectionMarshallingInfo collectionMarshalling - && collectionMarshalling.UseDefaultMarshalling - && collectionMarshalling.ElementCountInfo is NoCountInfo or SizeAndParamIndexInfo - && collectionMarshalling.ElementMarshallingInfo is NoMarshallingInfo or MarshalAsInfo { UnmanagedType: not UnmanagedType.CustomMarshaler } - ) - { - countInfo = collectionMarshalling.ElementCountInfo; - elementMarshallingInfo = collectionMarshalling.ElementMarshallingInfo; - } - else if (info.MarshallingAttributeInfo is MissingSupportCollectionMarshallingInfo missingSupport) - { - countInfo = missingSupport.CountInfo; - elementMarshallingInfo = missingSupport.ElementMarshallingInfo; - } - else - { - // This condition can be hit in two ways: - // 1. User uses the MarshalUsing attribute to provide count info or element marshalling information. - // Since the MarshalUsing attribute doesn't exist on downlevel platforms where we don't support arrays, - // this case is unlikely to come in supported scenarios, but could come up with a custom CoreLib implementation - // 2. User provides a MarsalAs attribute with the ArraySubType field set to UnmanagedType.CustomMarshaler - // As mentioned above, we don't support ICustomMarshaler in the generator so we fail to forward the attribute instead of partially fowarding it. - return false; - } - - List marshalAsArguments = new List - { - AttributeArgument( - CastExpression(ParseTypeName(TypeNames.System_Runtime_InteropServices_UnmanagedType), - LiteralExpression(SyntaxKind.NumericLiteralExpression, - Literal((int)UnmanagedType.LPArray)))) - }; - - if (countInfo is SizeAndParamIndexInfo sizeParamIndex) - { - if (sizeParamIndex.ConstSize != SizeAndParamIndexInfo.UnspecifiedConstSize) - { - marshalAsArguments.Add( - AttributeArgument(NameEquals("SizeConst"), null, - LiteralExpression(SyntaxKind.NumericLiteralExpression, - Literal(sizeParamIndex.ConstSize))) - ); - } - if (sizeParamIndex.ParamAtIndex is { ManagedIndex: int paramIndex }) - { - marshalAsArguments.Add( - AttributeArgument(NameEquals("SizeParamIndex"), null, - LiteralExpression(SyntaxKind.NumericLiteralExpression, - Literal(paramIndex))) - ); - } - } - - if (elementMarshallingInfo is MarshalAsInfo elementMarshalAs) - { - marshalAsArguments.Add( - AttributeArgument(NameEquals("ArraySubType"), null, - CastExpression(ParseTypeName(TypeNames.System_Runtime_InteropServices_UnmanagedType), - LiteralExpression(SyntaxKind.NumericLiteralExpression, - Literal((int)elementMarshalAs.UnmanagedType)))) - ); - } - marshalAsAttribute = Attribute(ParseName(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)) - .WithArgumentList(AttributeArgumentList(SeparatedList(marshalAsArguments))); - return true; - } - - return false; - } - - public ParameterSyntax AsParameter(TypePositionInfo info) - { - ParameterSyntax param = Parameter(Identifier(info.InstanceIdentifier)) - .WithModifiers(TokenList(Token(info.RefKindSyntax))) - .WithType(info.ManagedType.Syntax); - - List rehydratedAttributes = new(); - if (TryRehydrateMarshalAsAttribute(info, out AttributeSyntax marshalAsAttribute)) - { - rehydratedAttributes.Add(marshalAsAttribute); - } - if (info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.In)) - { - rehydratedAttributes.Add(Attribute(IdentifierName(TypeNames.System_Runtime_InteropServices_InAttribute))); - } - if (info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out)) - { - rehydratedAttributes.Add(Attribute(IdentifierName(TypeNames.System_Runtime_InteropServices_OutAttribute))); - } - - if (rehydratedAttributes.Count > 0) - { - param = param.AddAttributeLists(AttributeList(SeparatedList(rehydratedAttributes))); - } - - return param; + return SignatureBehavior.ManagedTypeAndAttributes; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { - return Argument(IdentifierName(info.InstanceIdentifier)) - .WithRefKindKeyword(Token(info.RefKindSyntax)); + return ValueBoundaryBehavior.ManagedIdentifier; } public IEnumerable Generate(TypePositionInfo info, StubCodeContext context) @@ -153,14 +38,5 @@ public IEnumerable Generate(TypePositionInfo info, StubCodeCont public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) => false; public bool SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, StubCodeContext context) => true; - - public AttributeListSyntax? GenerateAttributesForReturnType(TypePositionInfo info) - { - if (!TryRehydrateMarshalAsAttribute(info, out AttributeSyntax marshalAsAttribute)) - { - return null; - } - return AttributeList(SingletonSeparatedList(marshalAsAttribute)); - } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs index f1b4cc171aa9fd..2160d9f1be3bdc 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs @@ -18,8 +18,6 @@ internal interface ICustomNativeTypeMarshallingStrategy { TypeSyntax AsNativeType(TypePositionInfo info); - ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context); - IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context); IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments); @@ -47,20 +45,6 @@ public SimpleCustomNativeTypeMarshalling(TypeSyntax nativeTypeSyntax) _nativeTypeSyntax = nativeTypeSyntax; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) - { - string identifier = context.GetIdentifiers(info).native; - if (info.IsByRef) - { - return Argument( - PrefixUnaryExpression( - SyntaxKind.AddressOfExpression, - IdentifierName(identifier))); - } - - return Argument(IdentifierName(identifier)); - } - public TypeSyntax AsNativeType(TypePositionInfo info) { return _nativeTypeSyntax; @@ -159,20 +143,6 @@ public CustomNativeTypeWithValuePropertyMarshalling(ICustomNativeTypeMarshalling _valuePropertyType = valuePropertyType; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) - { - string identifier = context.GetIdentifiers(info).native; - if (info.IsByRef) - { - return Argument( - PrefixUnaryExpression( - SyntaxKind.AddressOfExpression, - IdentifierName(identifier))); - } - - return Argument(IdentifierName(identifier)); - } - public TypeSyntax AsNativeType(TypePositionInfo info) { return _valuePropertyType; @@ -287,11 +257,6 @@ public StackallocOptimizationMarshalling(ICustomNativeTypeMarshallingStrategy in _innerMarshaller = innerMarshaller; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.AsArgument(info, context); - } - public TypeSyntax AsNativeType(TypePositionInfo info) { return _innerMarshaller.AsNativeType(info); @@ -396,11 +361,6 @@ public FreeNativeCleanupStrategy(ICustomNativeTypeMarshallingStrategy innerMarsh _innerMarshaller = innerMarshaller; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.AsArgument(info, context); - } - public TypeSyntax AsNativeType(TypePositionInfo info) { return _innerMarshaller.AsNativeType(info); @@ -471,11 +431,6 @@ private bool CanPinMarshaller(TypePositionInfo info, StubCodeContext context) return context.SingleFrameSpansNativeContext && !info.IsManagedReturnPosition && !info.IsByRef || info.RefKind == RefKind.In; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.AsArgument(info, context); - } - public TypeSyntax AsNativeType(TypePositionInfo info) { return _valuePropertyType; @@ -608,11 +563,6 @@ public NumElementsExpressionMarshalling(ICustomNativeTypeMarshallingStrategy inn _sizeOfElementExpression = sizeOfElementExpression; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.AsArgument(info, context); - } - public TypeSyntax AsNativeType(TypePositionInfo info) { return _innerMarshaller.AsNativeType(info); @@ -721,11 +671,6 @@ public ContiguousBlittableElementCollectionMarshalling(ICustomNativeTypeMarshall _elementType = elementType; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.AsArgument(info, context); - } - public TypeSyntax AsNativeType(TypePositionInfo info) { return _innerMarshaller.AsNativeType(info); @@ -946,11 +891,6 @@ private StatementSyntax GenerateContentsMarshallingStatement(TypePositionInfo in return EmptyStatement(); } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) - { - return _innerMarshaller.AsArgument(info, context); - } - public TypeSyntax AsNativeType(TypePositionInfo info) { return _innerMarshaller.AsNativeType(info); diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshalAsMarshallingGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshalAsMarshallingGeneratorFactory.cs index e754c5469c3ca5..4355feac8a1934 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshalAsMarshallingGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshalAsMarshallingGeneratorFactory.cs @@ -13,7 +13,7 @@ public sealed class MarshalAsMarshallingGeneratorFactory : IMarshallingGenerator private static readonly VariantBoolMarshaller s_variantBool = new(); private static readonly Utf16CharMarshaller s_utf16Char = new(); - private static readonly Utf16StringMarshaller s_utf16String = new(); + private static readonly IMarshallingGenerator s_utf16String = new PinnableManagedValueMarshaller(new Utf16StringMarshaller()); private static readonly Utf8StringMarshaller s_utf8String = new(); private static readonly AnsiStringMarshaller s_ansiString = new AnsiStringMarshaller(s_utf8String); diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs index bad094d4ed3578..65ef66ce0438b3 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs @@ -20,6 +20,44 @@ public enum TargetFramework Net } + /// + /// An enumeration describing how a should be represented in its corresponding native signature element (parameter, field, or return value). + /// + public enum SignatureBehavior + { + /// + /// The native type should match the managed type, including rehydrating marshalling attributes and by-ref syntax (pure forwarding). + /// + ManagedTypeAndAttributes, + /// + /// The native signature should be the type returned by passed by value. + /// + NativeType, + /// + /// The native signature should be a pointer to the type returned by passed by value. + /// + PointerToNativeType + } + + /// + /// An enumeration describing how a should be represented in its corresponding native signature element (parameter, field, or return value). + /// + public enum ValueBoundaryBehavior + { + /// + /// The managed value should be passed as-is, including any managed by-ref syntax used in the managed declaration. + /// + ManagedIdentifier, + /// + /// The native identifier provided by should be passed by value. + /// + NativeIdentifier, + /// + /// The address of the native identifier provided by should be passed by value. + /// + AddressOfNativeIdentifier + } + /// /// Interface for generation of marshalling code for P/Invoke stubs /// @@ -41,19 +79,19 @@ public interface IMarshallingGenerator TypeSyntax AsNativeType(TypePositionInfo info); /// - /// Get the as a parameter of the P/Invoke declaration + /// Get shape that represents the provided in the native signature /// /// Object to marshal /// Parameter syntax for - ParameterSyntax AsParameter(TypePositionInfo info); + SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info); /// - /// Get the as an argument to be passed to the P/Invoke + /// Get shape of how the value represented by should be passed at the managed/native boundary in the provided /// /// Object to marshal /// Code generation context /// Argument syntax for - ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context); + ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context); /// /// Generate code for marshalling @@ -91,19 +129,6 @@ public interface IMarshallingGenerator bool SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, StubCodeContext context); } - /// - /// Interface for generating attributes for native return types. - /// - public interface IAttributedReturnTypeMarshallingGenerator : IMarshallingGenerator - { - /// - /// Gets any attributes that should be applied to the return type for this . - /// - /// Object to marshal - /// Attributes for the return type for this , or null if no attributes should be added. - AttributeListSyntax? GenerateAttributesForReturnType(TypePositionInfo info); - } - /// /// Exception used to indicate marshalling isn't supported. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs new file mode 100644 index 00000000000000..10f71426ae462f --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs @@ -0,0 +1,194 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Microsoft.Interop +{ + public static class MarshallingGeneratorExtensions + { + public static TypeSyntax AsReturnType(this IMarshallingGenerator generator, TypePositionInfo info) + { + return generator.GetNativeSignatureBehavior(info) switch + { + SignatureBehavior.ManagedTypeAndAttributes => info.ManagedType.Syntax, + SignatureBehavior.NativeType => generator.AsNativeType(info), + SignatureBehavior.PointerToNativeType => PointerType(generator.AsNativeType(info)), + _ => throw new InvalidOperationException() + }; + } + /// + /// Gets any attributes that should be applied to the return type for this . + /// + /// The marshalling generator for this + /// Object to marshal + /// Attributes for the return type for this , or null if no attributes should be added. + public static AttributeListSyntax? GenerateAttributesForReturnType(this IMarshallingGenerator generator, TypePositionInfo info) + { + if (generator.GetNativeSignatureBehavior(info) != SignatureBehavior.ManagedTypeAndAttributes) + { + return null; + } + + if (!TryRehydrateMarshalAsAttribute(info, out AttributeSyntax marshalAsAttribute)) + { + return null; + } + return AttributeList(SingletonSeparatedList(marshalAsAttribute)); + } + + public static ParameterSyntax AsParameter(this IMarshallingGenerator generator, TypePositionInfo info) + { + SignatureBehavior behavior = generator.GetNativeSignatureBehavior(info); + if (behavior == SignatureBehavior.ManagedTypeAndAttributes) + { + return GenerateForwardingParameter(info); + } + return Parameter(Identifier(info.InstanceIdentifier)) + .WithType(behavior switch + { + SignatureBehavior.NativeType => generator.AsNativeType(info), + SignatureBehavior.PointerToNativeType => PointerType(generator.AsNativeType(info)), + _ => throw new InvalidOperationException() + }); + } + + private static ParameterSyntax GenerateForwardingParameter(TypePositionInfo info) + { + ParameterSyntax param = Parameter(Identifier(info.InstanceIdentifier)) + .WithModifiers(TokenList(Token(info.RefKindSyntax))) + .WithType(info.ManagedType.Syntax); + + List rehydratedAttributes = new(); + if (TryRehydrateMarshalAsAttribute(info, out AttributeSyntax marshalAsAttribute)) + { + rehydratedAttributes.Add(marshalAsAttribute); + } + if (info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.In)) + { + rehydratedAttributes.Add(Attribute(IdentifierName(TypeNames.System_Runtime_InteropServices_InAttribute))); + } + if (info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out)) + { + rehydratedAttributes.Add(Attribute(IdentifierName(TypeNames.System_Runtime_InteropServices_OutAttribute))); + } + + if (rehydratedAttributes.Count > 0) + { + param = param.AddAttributeLists(AttributeList(SeparatedList(rehydratedAttributes))); + } + + return param; + } + + + private static bool TryRehydrateMarshalAsAttribute(TypePositionInfo info, out AttributeSyntax marshalAsAttribute) + { + marshalAsAttribute = null!; + // If the parameter has [MarshalAs] marshalling, we resurface that + // in the forwarding target since the built-in system understands it. + // ICustomMarshaller marshalling requires additional information that we throw away earlier since it's unsupported, + // so explicitly do not resurface a [MarshalAs(UnmanagdType.CustomMarshaler)] attribute. + if (info.MarshallingAttributeInfo is MarshalAsInfo { UnmanagedType: not UnmanagedType.CustomMarshaler } marshalAs) + { + marshalAsAttribute = Attribute(ParseName(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)) + .WithArgumentList(AttributeArgumentList(SingletonSeparatedList(AttributeArgument( + CastExpression(ParseTypeName(TypeNames.System_Runtime_InteropServices_UnmanagedType), + LiteralExpression(SyntaxKind.NumericLiteralExpression, + Literal((int)marshalAs.UnmanagedType))))))); + return true; + } + + if (info.ManagedType is SzArrayType) + { + CountInfo countInfo; + MarshallingInfo elementMarshallingInfo; + if (info.MarshallingAttributeInfo is NativeContiguousCollectionMarshallingInfo collectionMarshalling + && collectionMarshalling.UseDefaultMarshalling + && collectionMarshalling.ElementCountInfo is NoCountInfo or SizeAndParamIndexInfo + && collectionMarshalling.ElementMarshallingInfo is NoMarshallingInfo or MarshalAsInfo { UnmanagedType: not UnmanagedType.CustomMarshaler } + ) + { + countInfo = collectionMarshalling.ElementCountInfo; + elementMarshallingInfo = collectionMarshalling.ElementMarshallingInfo; + } + else if (info.MarshallingAttributeInfo is MissingSupportCollectionMarshallingInfo missingSupport) + { + countInfo = missingSupport.CountInfo; + elementMarshallingInfo = missingSupport.ElementMarshallingInfo; + } + else + { + // This condition can be hit in two ways: + // 1. User uses the MarshalUsing attribute to provide count info or element marshalling information. + // Since the MarshalUsing attribute doesn't exist on downlevel platforms where we don't support arrays, + // this case is unlikely to come in supported scenarios, but could come up with a custom CoreLib implementation + // 2. User provides a MarsalAs attribute with the ArraySubType field set to UnmanagedType.CustomMarshaler + // As mentioned above, we don't support ICustomMarshaler in the generator so we fail to forward the attribute instead of partially fowarding it. + return false; + } + + List marshalAsArguments = new List + { + AttributeArgument( + CastExpression(ParseTypeName(TypeNames.System_Runtime_InteropServices_UnmanagedType), + LiteralExpression(SyntaxKind.NumericLiteralExpression, + Literal((int)UnmanagedType.LPArray)))) + }; + + if (countInfo is SizeAndParamIndexInfo sizeParamIndex) + { + if (sizeParamIndex.ConstSize != SizeAndParamIndexInfo.UnspecifiedConstSize) + { + marshalAsArguments.Add( + AttributeArgument(NameEquals("SizeConst"), null, + LiteralExpression(SyntaxKind.NumericLiteralExpression, + Literal(sizeParamIndex.ConstSize))) + ); + } + if (sizeParamIndex.ParamAtIndex is { ManagedIndex: int paramIndex }) + { + marshalAsArguments.Add( + AttributeArgument(NameEquals("SizeParamIndex"), null, + LiteralExpression(SyntaxKind.NumericLiteralExpression, + Literal(paramIndex))) + ); + } + } + + if (elementMarshallingInfo is MarshalAsInfo elementMarshalAs) + { + marshalAsArguments.Add( + AttributeArgument(NameEquals("ArraySubType"), null, + CastExpression(ParseTypeName(TypeNames.System_Runtime_InteropServices_UnmanagedType), + LiteralExpression(SyntaxKind.NumericLiteralExpression, + Literal((int)elementMarshalAs.UnmanagedType)))) + ); + } + marshalAsAttribute = Attribute(ParseName(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)) + .WithArgumentList(AttributeArgumentList(SeparatedList(marshalAsArguments))); + return true; + } + + return false; + } + + public static ArgumentSyntax AsArgument(this IMarshallingGenerator generator, TypePositionInfo info, StubCodeContext context) + { + (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); + return generator.GetValueBoundaryBehavior(info, context) switch + { + ValueBoundaryBehavior.ManagedIdentifier when !info.IsByRef => Argument(IdentifierName(managedIdentifier)), + ValueBoundaryBehavior.ManagedIdentifier when info.IsByRef => Argument(IdentifierName(managedIdentifier)).WithRefKindKeyword(Token(info.RefKindSyntax)), + ValueBoundaryBehavior.NativeIdentifier => Argument(IdentifierName(nativeIdentifier)), + ValueBoundaryBehavior.AddressOfNativeIdentifier => Argument(PrefixUnaryExpression(SyntaxKind.AddressOfExpression, IdentifierName(nativeIdentifier))), + _ => throw new InvalidOperationException() + }; + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs index e5890d04e95671..191713bbf019f4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs @@ -11,34 +11,33 @@ namespace Microsoft.Interop { public sealed class PinnableManagedValueMarshaller : IMarshallingGenerator { - private readonly IMarshallingGenerator _manualMarshallingGenerator; + private readonly IMarshallingGenerator _innerMarshallingGenerator; - public PinnableManagedValueMarshaller(IMarshallingGenerator manualMarshallingGenerator) + public PinnableManagedValueMarshaller(IMarshallingGenerator innerMarshallingGenerator) { - _manualMarshallingGenerator = manualMarshallingGenerator; + _innerMarshallingGenerator = innerMarshallingGenerator; } public bool IsSupported(TargetFramework target, Version version) - => _manualMarshallingGenerator.IsSupported(target, version); + => _innerMarshallingGenerator.IsSupported(target, version); - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { if (IsPinningPathSupported(info, context)) { - string identifier = context.GetIdentifiers(info).native; - return Argument(CastExpression(AsNativeType(info), IdentifierName(identifier))); + return ValueBoundaryBehavior.NativeIdentifier; } - return _manualMarshallingGenerator.AsArgument(info, context); + return _innerMarshallingGenerator.GetValueBoundaryBehavior(info, context); } public TypeSyntax AsNativeType(TypePositionInfo info) { - return _manualMarshallingGenerator.AsNativeType(info); + return _innerMarshallingGenerator.AsNativeType(info); } - public ParameterSyntax AsParameter(TypePositionInfo info) + public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - return _manualMarshallingGenerator.AsParameter(info); + return _innerMarshallingGenerator.GetNativeSignatureBehavior(info); } public IEnumerable Generate(TypePositionInfo info, StubCodeContext context) @@ -47,12 +46,12 @@ public IEnumerable Generate(TypePositionInfo info, StubCodeCont { return GeneratePinningPath(info, context); } - return _manualMarshallingGenerator.Generate(info, context); + return _innerMarshallingGenerator.Generate(info, context); } public bool SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, StubCodeContext context) { - return _manualMarshallingGenerator.SupportsByValueMarshalKind(marshalKind, context); + return _innerMarshallingGenerator.SupportsByValueMarshalKind(marshalKind, context); } public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) @@ -61,7 +60,7 @@ public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) { return false; } - return _manualMarshallingGenerator.UsesNativeIdentifier(info, context); + return _innerMarshallingGenerator.UsesNativeIdentifier(info, context); } private static bool IsPinningPathSupported(TypePositionInfo info, StubCodeContext context) { @@ -73,17 +72,26 @@ private IEnumerable GeneratePinningPath(TypePositionInfo info, if (context.CurrentStage == StubCodeContext.Stage.Pin) { (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); + string pinnedIdentifier = context.GetAdditionalIdentifier(info, "pinned"); yield return FixedStatement( VariableDeclaration( PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword))), SingletonSeparatedList( - VariableDeclarator(Identifier(nativeIdentifier)) + VariableDeclarator(Identifier(pinnedIdentifier)) .WithInitializer(EqualsValueClause( IdentifierName(managedIdentifier) )) ) ), - EmptyStatement() + // = (); + LocalDeclarationStatement( + VariableDeclaration(AsNativeType(info), + SingletonSeparatedList( + VariableDeclarator(nativeIdentifier) + .WithInitializer(EqualsValueClause( + CastExpression( + AsNativeType(info), + IdentifierName(pinnedIdentifier))))))) ); } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs index 59dc0b6001bd21..363fc3846637af 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs @@ -23,27 +23,14 @@ public TypeSyntax AsNativeType(TypePositionInfo info) return MarshallerHelpers.SystemIntPtrType; } - public ParameterSyntax AsParameter(TypePositionInfo info) + public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - TypeSyntax type = info.IsByRef - ? PointerType(AsNativeType(info)) - : AsNativeType(info); - return Parameter(Identifier(info.InstanceIdentifier)) - .WithType(type); + return info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType; } - public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { - string identifier = context.GetIdentifiers(info).native; - if (info.IsByRef) - { - return Argument( - PrefixUnaryExpression( - SyntaxKind.AddressOfExpression, - IdentifierName(identifier))); - } - - return Argument(IdentifierName(identifier)); + return info.IsByRef ? ValueBoundaryBehavior.AddressOfNativeIdentifier : ValueBoundaryBehavior.NativeIdentifier; } public IEnumerable Generate(TypePositionInfo info, StubCodeContext context) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Ansi.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Ansi.cs index 40c09b0ed1890d..d279cb5d486e96 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Ansi.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Ansi.cs @@ -23,38 +23,20 @@ public AnsiStringMarshaller(Utf8StringMarshaller utf8StringMarshaller) _utf8StringMarshaller = utf8StringMarshaller; } - public override ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public override SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - string identifier = context.GetIdentifiers(info).native; - if (info.IsByRef) - { - // & - return Argument( - PrefixUnaryExpression( - SyntaxKind.AddressOfExpression, - IdentifierName(identifier))); - } - - // - return Argument(IdentifierName(identifier)); + return info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType; } - public override TypeSyntax AsNativeType(TypePositionInfo info) + public override ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { - // byte* - return s_nativeType; + return info.IsByRef ? ValueBoundaryBehavior.AddressOfNativeIdentifier : ValueBoundaryBehavior.NativeIdentifier; } - public override ParameterSyntax AsParameter(TypePositionInfo info) + public override TypeSyntax AsNativeType(TypePositionInfo info) { - // byte** - // or // byte* - TypeSyntax type = info.IsByRef - ? PointerType(AsNativeType(info)) - : AsNativeType(info); - return Parameter(Identifier(info.InstanceIdentifier)) - .WithType(type); + return s_nativeType; } public override IEnumerable Generate(TypePositionInfo info, StubCodeContext context) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf16.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf16.cs index 979d806d4c0fcd..956098935e6bd2 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf16.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf16.cs @@ -20,69 +20,25 @@ public sealed class Utf16StringMarshaller : ConditionalStackallocMarshallingGene private static readonly TypeSyntax s_nativeType = PointerType(PredefinedType(Token(SyntaxKind.UShortKeyword))); - private static string PinnedIdentifier(string nativeIdentifier) => $"{nativeIdentifier}__pinned"; - - public override ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public override SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - string identifier = context.GetIdentifiers(info).native; - if (info.IsByRef) - { - // & - return Argument( - PrefixUnaryExpression( - SyntaxKind.AddressOfExpression, - IdentifierName(identifier))); - } - else if (context.SingleFrameSpansNativeContext) - { - // (ushort*) - return Argument( - CastExpression( - AsNativeType(info), - IdentifierName(PinnedIdentifier(identifier)))); - } - - // - return Argument(IdentifierName(identifier)); + return info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType; } - public override TypeSyntax AsNativeType(TypePositionInfo info) + public override ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { - // ushort* - return s_nativeType; + return info.IsByRef ? ValueBoundaryBehavior.AddressOfNativeIdentifier : ValueBoundaryBehavior.NativeIdentifier; } - public override ParameterSyntax AsParameter(TypePositionInfo info) + public override TypeSyntax AsNativeType(TypePositionInfo info) { - // ushort** - // or // ushort* - TypeSyntax type = info.IsByRef - ? PointerType(AsNativeType(info)) - : AsNativeType(info); - return Parameter(Identifier(info.InstanceIdentifier)) - .WithType(type); + return s_nativeType; } public override IEnumerable Generate(TypePositionInfo info, StubCodeContext context) { (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); - if (context.SingleFrameSpansNativeContext && !info.IsByRef && !info.IsManagedReturnPosition) - { - if (context.CurrentStage == StubCodeContext.Stage.Pin) - { - // fixed (char* = ) - yield return FixedStatement( - VariableDeclaration( - PointerType(PredefinedType(Token(SyntaxKind.CharKeyword))), - SingletonSeparatedList( - VariableDeclarator(Identifier(PinnedIdentifier(nativeIdentifier))) - .WithInitializer(EqualsValueClause(IdentifierName(managedIdentifier))))), - EmptyStatement()); - } - - yield break; - } switch (context.CurrentStage) { @@ -135,7 +91,7 @@ public override IEnumerable Generate(TypePositionInfo info, Stu } public override bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) - => info.IsManagedReturnPosition || info.IsByRef || !context.SingleFrameSpansNativeContext; + => true; public override bool SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, StubCodeContext context) => false; @@ -216,7 +172,7 @@ protected override StatementSyntax GenerateStackallocOnlyValueMarshalling( PointerType(PredefinedType(Token(SyntaxKind.CharKeyword))), IdentifierName(stackAllocPtrIdentifier))), BracketedArgumentList( - SingletonSeparatedList( + SingletonSeparatedList( Argument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf8.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf8.cs index 8414b271b0ef6f..1774811838fb64 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf8.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf8.cs @@ -29,31 +29,18 @@ public sealed class Utf8StringMarshaller : ConditionalStackallocMarshallingGener private static readonly TypeSyntax s_nativeType = PointerType(PredefinedType(Token(SyntaxKind.ByteKeyword))); private static readonly TypeSyntax s_utf8EncodingType = ParseTypeName("System.Text.Encoding.UTF8"); - public override ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context) + public override SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { - string identifier = context.GetIdentifiers(info).native; - if (info.IsByRef) - { - return Argument( - PrefixUnaryExpression( - SyntaxKind.AddressOfExpression, - IdentifierName(identifier))); - } - - return Argument(IdentifierName(identifier)); + return info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType; } - public override TypeSyntax AsNativeType(TypePositionInfo info) => s_nativeType; - - public override ParameterSyntax AsParameter(TypePositionInfo info) + public override ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { - TypeSyntax type = info.IsByRef - ? PointerType(AsNativeType(info)) - : AsNativeType(info); - return Parameter(Identifier(info.InstanceIdentifier)) - .WithType(type); + return info.IsByRef ? ValueBoundaryBehavior.AddressOfNativeIdentifier : ValueBoundaryBehavior.NativeIdentifier; } + public override TypeSyntax AsNativeType(TypePositionInfo info) => s_nativeType; + public override IEnumerable Generate(TypePositionInfo info, StubCodeContext context) { (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); From eb291316bb6cc2a0cd0d189a0c44adde63c54091 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 18 Mar 2022 15:41:14 -0700 Subject: [PATCH 2/2] Add some docs --- .../MarshallingGeneratorExtensions.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs index 10f71426ae462f..6cd7da3f430570 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs @@ -12,6 +12,11 @@ namespace Microsoft.Interop { public static class MarshallingGeneratorExtensions { + /// + /// Gets the return type for the unmanaged signature that represents the provided . + /// + /// The marshalling generator for this + /// Object to marshal public static TypeSyntax AsReturnType(this IMarshallingGenerator generator, TypePositionInfo info) { return generator.GetNativeSignatureBehavior(info) switch @@ -42,6 +47,11 @@ public static TypeSyntax AsReturnType(this IMarshallingGenerator generator, Type return AttributeList(SingletonSeparatedList(marshalAsAttribute)); } + /// + /// Gets a parameter for the unmanaged signature that represents the provided . + /// + /// The marshalling generator for this + /// Object to marshal public static ParameterSyntax AsParameter(this IMarshallingGenerator generator, TypePositionInfo info) { SignatureBehavior behavior = generator.GetNativeSignatureBehavior(info); @@ -178,6 +188,12 @@ private static bool TryRehydrateMarshalAsAttribute(TypePositionInfo info, out At return false; } + /// + /// Gets an argument expression for the unmanaged signature that can be used to pass a value of the provided in the specified . + /// + /// The marshalling generator for this + /// Object to marshal + /// Marshalling context public static ArgumentSyntax AsArgument(this IMarshallingGenerator generator, TypePositionInfo info, StubCodeContext context) { (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);