From d25c6ec4bd69d3ecaff8a4700dd8d11f54edf199 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Jul 2022 15:33:18 -0700 Subject: [PATCH 1/8] Move ArrayMarshaller and PointerArrayMarshaller to the v2 design Remove the built-in custom array pinning code as we don't need it any more (it's implemented on the marshallers themselves with the static GetPinnableReference method) --- .../System.Private.CoreLib.Shared.projitems | 1 + .../Marshalling/ArrayMarshaller.cs | 256 +++++++++--------- ...ContiguousCollectionMarshallerAttribute.cs | 0 .../Marshalling/PointerArrayMarshaller.cs | 253 +++++++++-------- .../Marshalling/ArrayMarshaller.cs | 162 ----------- ...ributedMarshallingModelGeneratorFactory.cs | 57 ++-- .../MarshallingGeneratorExtensions.cs | 21 +- .../MarshallingAttributeInfo.cs | 24 +- .../TypeNames.cs | 8 +- .../ref/System.Runtime.InteropServices.cs | 110 +++++--- 10 files changed, 384 insertions(+), 508 deletions(-) rename src/libraries/{System.Runtime.InteropServices/tests/Ancillary.Interop => System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling}/ContiguousCollectionMarshallerAttribute.cs (100%) delete mode 100644 src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index d978ef0b8c488..4b6bee8d22bd9 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -872,6 +872,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs index 07386d0864c62..0f177dc522510 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs @@ -10,147 +10,153 @@ namespace System.Runtime.InteropServices.Marshalling /// Marshaller for arrays /// /// Array element type + /// The unmanaged type for the element type [CLSCompliant(false)] - [CustomTypeMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), - CustomTypeMarshallerKind.LinearCollection, BufferSize = 0x200, - Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling)] - public unsafe ref struct ArrayMarshaller + [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), + MarshalMode.Default, + typeof(ArrayMarshaller<,>))] + [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), + MarshalMode.ManagedToUnmanagedIn, + typeof(ArrayMarshaller<,>.ManagedToUnmanagedIn))] + [ContiguousCollectionMarshaller] + public static unsafe class ArrayMarshaller + where TUnmanagedElement : unmanaged { - private readonly int _sizeOfNativeElement; - - private T[]? _managedArray; - private IntPtr _allocatedMemory; - private Span _span; - - /// - /// Initializes a new instance of the . - /// - /// Size of the native element in bytes. - public ArrayMarshaller(int sizeOfNativeElement) - : this() + public static byte* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) { - _sizeOfNativeElement = sizeOfNativeElement; - } - - /// - /// Initializes a new instance of the . - /// - /// Array to be marshalled. - /// Size of the native element in bytes. - public ArrayMarshaller(T[]? array, int sizeOfNativeElement) - : this(array, Span.Empty, sizeOfNativeElement) - { } - - /// - /// Initializes a new instance of the . - /// - /// Array to be marshalled. - /// Buffer that may be used for marshalling. - /// Size of the native element in bytes. - /// - /// The must not be movable - that is, it should not be - /// on the managed heap or it should be pinned. - /// - /// - public ArrayMarshaller(T[]? array, Span buffer, int sizeOfNativeElement) - { - _allocatedMemory = default; - _sizeOfNativeElement = sizeOfNativeElement; - if (array is null) + if (managed is null) { - _managedArray = null; - _span = default; - return; + numElements = 0; + return null; } - _managedArray = array; + numElements = managed.Length; // Always allocate at least one byte when the array is zero-length. - int bufferSize = checked(array.Length * _sizeOfNativeElement); - int spaceToAllocate = Math.Max(bufferSize, 1); - if (spaceToAllocate <= buffer.Length) - { - _span = buffer[0..spaceToAllocate]; - } - else - { - _allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate); - _span = new Span((void*)_allocatedMemory, spaceToAllocate); - } + int spaceToAllocate = Math.Max(checked(sizeof(TUnmanagedElement) * numElements), 1); + return (byte*)Marshal.AllocCoTaskMem(spaceToAllocate); } - /// - /// Gets a span that points to the memory where the managed values of the array are stored. - /// - /// Span over managed values of the array. - /// - public ReadOnlySpan GetManagedValuesSource() => _managedArray; - - /// - /// Gets a span that points to the memory where the unmarshalled managed values of the array should be stored. - /// - /// Length of the array. - /// Span where managed values of the array should be stored. - /// - public Span GetManagedValuesDestination(int length) => _allocatedMemory == IntPtr.Zero ? null : _managedArray = new T[length]; - - /// - /// Returns a span that points to the memory where the native values of the array are stored after the native call. - /// - /// Length of the array. - /// Span over the native values of the array. - /// - public ReadOnlySpan GetNativeValuesSource(int length) - { - if (_allocatedMemory == IntPtr.Zero) - return default; + public static ReadOnlySpan GetManagedValuesSource(T[]? managed) + => managed; - int allocatedSize = checked(length * _sizeOfNativeElement); - _span = new Span((void*)_allocatedMemory, allocatedSize); - return _span; - } + public static Span GetUnmanagedValuesDestination(byte* unmanaged, int numElements) + => new Span(unmanaged, numElements); - /// - /// Returns a span that points to the memory where the native values of the array should be stored. - /// - /// Span where native values of the array should be stored. - /// - public Span GetNativeValuesDestination() => _span; - - /// - /// Returns a reference to the marshalled array. - /// - public ref byte GetPinnableReference() => ref MemoryMarshal.GetReference(_span); - - /// - /// Returns the native value representing the array. - /// - /// - public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference()); - - /// - /// Sets the native value representing the array. - /// - /// The native value. - /// - public void FromNativeValue(byte* value) + public static T[]? AllocateContainerForManagedElements(byte* unmanaged, int length) { - _allocatedMemory = (IntPtr)value; + if (unmanaged is null) + return null; + + return new T[length]; } - /// - /// Returns the managed array. - /// - /// - public T[]? ToManaged() => _managedArray; - - /// - /// Frees native resources. - /// - /// - public void FreeNative() + public static Span GetManagedValuesDestination(T[]? managed) + => managed; + + public static ReadOnlySpan GetUnmanagedValuesSource(byte* unmanagedValue, int numElements) + => new ReadOnlySpan(unmanagedValue, numElements); + + public static void Free(byte* unmanaged) + => Marshal.FreeCoTaskMem((IntPtr)unmanaged); + + public ref struct ManagedToUnmanagedIn { - Marshal.FreeCoTaskMem(_allocatedMemory); + // We'll keep the buffer size at a maximum of 200 bytes to avoid overflowing the stack. + public static int BufferSize { get; } = 0x200 / sizeof(TUnmanagedElement); + + private T[]? _managedArray; + private TUnmanagedElement* _allocatedMemory; + private Span _span; + + /// + /// Initializes the marshaller. + /// + /// Array to be marshalled. + /// Buffer that may be used for marshalling. + /// + /// The must not be movable - that is, it should not be + /// on the managed heap or it should be pinned. + /// + public void FromManaged(T[]? array, Span buffer) + { + _allocatedMemory = null; + if (array is null) + { + _managedArray = null; + _span = default; + return; + } + + _managedArray = array; + + // Always allocate at least one byte when the array is zero-length. + if (array.Length <= buffer.Length) + { + _span = buffer[0..array.Length]; + } + else + { + int bufferSize = checked(array.Length * sizeof(TUnmanagedElement)); + int spaceToAllocate = Math.Max(bufferSize, 1); + _allocatedMemory = (TUnmanagedElement*)NativeMemory.Alloc((nuint)spaceToAllocate); + _span = new Span(_allocatedMemory, array.Length); + } + } + + /// + /// Gets a span that points to the memory where the managed values of the array are stored. + /// + /// Span over managed values of the array. + public ReadOnlySpan GetManagedValuesSource() => _managedArray; + + /// + /// Returns a span that points to the memory where the unmanaged values of the array should be stored. + /// + /// Span where unmanaged values of the array should be stored. + public Span GetUnmanagedValuesDestination() => _span; + + /// + /// Returns a reference to the marshalled array. + /// + public ref TUnmanagedElement GetPinnableReference() => ref MemoryMarshal.GetReference(_span); + + /// + /// Returns the unmanaged value representing the array. + /// + public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)Unsafe.AsPointer(ref GetPinnableReference()); + + /// + /// Sets the unmanaged value representing the array. + /// + /// The unmanaged value. + public void FromUnmanaged(TUnmanagedElement* value) + { + _allocatedMemory = value; + } + + /// + /// Returns the managed array. + /// + /// + public T[]? ToManaged() => _managedArray; + + /// + /// Frees resources. + /// + public void Free() + { + NativeMemory.Free(_allocatedMemory); + } + + public static ref T GetPinnableReference(T[]? array) + { + if (array is null) + { + return ref Unsafe.NullRef(); + } + return ref MemoryMarshal.GetArrayDataReference(array); + } } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ContiguousCollectionMarshallerAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ContiguousCollectionMarshallerAttribute.cs similarity index 100% rename from src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ContiguousCollectionMarshallerAttribute.cs rename to src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ContiguousCollectionMarshallerAttribute.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs index 03e2f3d245926..e93ca95d5aa2f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs @@ -10,151 +10,150 @@ namespace System.Runtime.InteropServices.Marshalling /// Marshaller for arrays of pointers /// /// Array element pointer type + /// The unmanaged type for the element pointer type [CLSCompliant(false)] - [CustomTypeMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), - CustomTypeMarshallerKind.LinearCollection, BufferSize = 0x200, - Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.CallerAllocatedBuffer | CustomTypeMarshallerFeatures.TwoStageMarshalling)] - public unsafe ref struct PointerArrayMarshaller where T : unmanaged + [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), + MarshalMode.Default, + typeof(PointerArrayMarshaller<,>))] + [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), + MarshalMode.ManagedToUnmanagedIn, + typeof(PointerArrayMarshaller<,>.ManagedToUnmanagedIn))] + [ContiguousCollectionMarshaller] + public static unsafe class PointerArrayMarshaller + where T : unmanaged + where TUnmanagedElement : unmanaged { - private readonly int _sizeOfNativeElement; - - private T*[]? _managedArray; - private IntPtr _allocatedMemory; - private Span _span; - - /// - /// Initializes a new instance of the . - /// - /// Size of the native element in bytes. - public PointerArrayMarshaller(int sizeOfNativeElement) - : this() + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T*[]? managed, out int numElements) { - _sizeOfNativeElement = sizeOfNativeElement; - } - - /// - /// Initializes a new instance of the . - /// - /// Array to be marshalled. - /// Size of the native element in bytes. - public PointerArrayMarshaller(T*[]? array, int sizeOfNativeElement) - : this(array, Span.Empty, sizeOfNativeElement) - { } - - /// - /// Initializes a new instance of the . - /// - /// Array to be marshalled. - /// Buffer that may be used for marshalling. - /// Size of the native element in bytes. - /// - /// The must not be movable - that is, it should not be - /// on the managed heap or it should be pinned. - /// - /// - public PointerArrayMarshaller(T*[]? array, Span buffer, int sizeOfNativeElement) - { - _allocatedMemory = default; - _sizeOfNativeElement = sizeOfNativeElement; - if (array is null) + if (managed is null) { - _managedArray = null; - _span = default; - return; + numElements = 0; + return null; } - _managedArray = array; + numElements = managed.Length; // Always allocate at least one byte when the array is zero-length. - int bufferSize = checked(array.Length * _sizeOfNativeElement); - int spaceToAllocate = Math.Max(bufferSize, 1); - if (spaceToAllocate <= buffer.Length) - { - _span = buffer[0..spaceToAllocate]; - } - else - { - _allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate); - _span = new Span((void*)_allocatedMemory, spaceToAllocate); - } + int spaceToAllocate = Math.Max(checked(sizeof(TUnmanagedElement) * numElements), 1); + return (TUnmanagedElement*)Marshal.AllocCoTaskMem(spaceToAllocate); } - /// - /// Gets a span that points to the memory where the managed values of the array are stored. - /// - /// Span over managed values of the array. - /// - public ReadOnlySpan GetManagedValuesSource() => Unsafe.As(_managedArray); - - /// - /// Gets a span that points to the memory where the unmarshalled managed values of the array should be stored. - /// - /// Length of the array. - /// Span where managed values of the array should be stored. - /// - public Span GetManagedValuesDestination(int length) + public static ReadOnlySpan GetManagedValuesSource(T*[]? managed) + => Unsafe.As(managed); + + public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) + => new Span(unmanaged, numElements); + + public static T*[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int length) { - if (_allocatedMemory == IntPtr.Zero) + if (unmanaged is null) return null; - _managedArray = new T*[length]; - return Unsafe.As(_managedArray); + return new T*[length]; } - /// - /// Returns a span that points to the memory where the native values of the array are stored after the native call. - /// - /// Length of the array. - /// Span over the native values of the array. - /// - public ReadOnlySpan GetNativeValuesSource(int length) - { - if (_allocatedMemory == IntPtr.Zero) - return default; + public static Span GetManagedValuesDestination(T*[]? managed) + => Unsafe.As(managed); - int allocatedSize = checked(length * _sizeOfNativeElement); - _span = new Span((void*)_allocatedMemory, allocatedSize); - return _span; - } + public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements) + => new ReadOnlySpan(unmanagedValue, numElements); + + public static void Free(TUnmanagedElement* unmanaged) + => Marshal.FreeCoTaskMem((IntPtr)unmanaged); - /// - /// Returns a span that points to the memory where the native values of the array should be stored. - /// - /// Span where native values of the array should be stored. - /// - public Span GetNativeValuesDestination() => _span; - - /// - /// Returns a reference to the marshalled array. - /// - public ref byte GetPinnableReference() => ref MemoryMarshal.GetReference(_span); - - /// - /// Returns the native value representing the array. - /// - /// - public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference()); - - /// - /// Sets the native value representing the array. - /// - /// The native value. - /// - public void FromNativeValue(byte* value) => _allocatedMemory = (IntPtr)value; - - /// - /// Returns the managed array. - /// - /// - public T*[]? ToManaged() => _managedArray; - - /// - /// Frees native resources. - /// - /// - public void FreeNative() + public ref struct ManagedToUnmanagedIn { - Marshal.FreeCoTaskMem(_allocatedMemory); + public static int BufferSize => 0x200 / sizeof(TUnmanagedElement); + + private T*[]? _managedArray; + private TUnmanagedElement* _allocatedMemory; + private Span _span; + + /// + /// Initializes the marshaller. + /// + /// Array to be marshalled. + /// Buffer that may be used for marshalling. + /// + /// The must not be movable - that is, it should not be + /// on the managed heap or it should be pinned. + /// + public void FromManaged(T*[]? array, Span buffer) + { + _allocatedMemory = null; + if (array is null) + { + _managedArray = null; + _span = default; + return; + } + + _managedArray = array; + + // Always allocate at least one byte when the array is zero-length. + if (array.Length <= buffer.Length) + { + _span = buffer[0..array.Length]; + } + else + { + int bufferSize = checked(array.Length * sizeof(TUnmanagedElement)); + int spaceToAllocate = Math.Max(bufferSize, 1); + _allocatedMemory = (TUnmanagedElement*)NativeMemory.Alloc((nuint)spaceToAllocate); + _span = new Span(_allocatedMemory, array.Length); + } + } + + /// + /// Gets a span that points to the memory where the managed values of the array are stored. + /// + /// Span over managed values of the array. + public ReadOnlySpan GetManagedValuesSource() => Unsafe.As(_managedArray); + + /// + /// Returns a span that points to the memory where the unmanaged values of the array should be stored. + /// + /// Span where unmanaged values of the array should be stored. + public Span GetUnmanagedValuesDestination() => _span; + + /// + /// Returns a reference to the marshalled array. + /// + public ref TUnmanagedElement GetPinnableReference() => ref MemoryMarshal.GetReference(_span); + + /// + /// Returns the unmanaged value representing the array. + /// + public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)Unsafe.AsPointer(ref GetPinnableReference()); + + /// + /// Sets the unmanaged value representing the array. + /// + /// The unmanaged value. + public void FromUnmanaged(TUnmanagedElement* value) => _allocatedMemory = value; + + /// + /// Returns the managed array. + /// + /// + public T*[]? ToManaged() => _managedArray; + + /// + /// Frees resources. + /// + public void Free() + { + NativeMemory.Free(_allocatedMemory); + } + + public static ref byte GetPinnableReference(T*[]? array) + { + if (array is null) + { + return ref Unsafe.NullRef(); + } + return ref MemoryMarshal.GetArrayDataReference(array); + } } } } 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 deleted file mode 100644 index 0b41be2390e9d..0000000000000 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs +++ /dev/null @@ -1,162 +0,0 @@ -// 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 Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; - -namespace Microsoft.Interop -{ - public sealed class ArrayMarshaller : IMarshallingGenerator - { - private readonly IMarshallingGenerator _manualMarshallingGenerator; - private readonly TypePositionInfo _elementInfo; - private readonly bool _enablePinning; - - public ArrayMarshaller(IMarshallingGenerator manualMarshallingGenerator, TypePositionInfo elementInfo, bool enablePinning) - { - _manualMarshallingGenerator = manualMarshallingGenerator; - _elementInfo = elementInfo; - _enablePinning = enablePinning; - } - - public bool IsSupported(TargetFramework target, Version version) - { - return target is TargetFramework.Net && version.Major >= 7; - } - - public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) - { - if (IsPinningPathSupported(info, context)) - { - if (AsNativeType(info) is PointerTypeSyntax pointerType - && pointerType.ElementType is PredefinedTypeSyntax predefinedType - && predefinedType.Keyword.IsKind(SyntaxKind.VoidKeyword)) - { - return ValueBoundaryBehavior.NativeIdentifier; - } - - // Cast to native type if it is not void* - return ValueBoundaryBehavior.CastNativeIdentifier; - } - return _manualMarshallingGenerator.GetValueBoundaryBehavior(info, context); - } - - public TypeSyntax AsNativeType(TypePositionInfo info) - { - return _manualMarshallingGenerator.AsNativeType(info); - } - - public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) - { - return _manualMarshallingGenerator.GetNativeSignatureBehavior(info); - } - - public IEnumerable Generate(TypePositionInfo info, StubCodeContext context) - { - if (IsPinningPathSupported(info, context)) - { - return GeneratePinningPath(info, context); - } - return _manualMarshallingGenerator.Generate(info, context); - } - - public bool SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, StubCodeContext context) - { - if (context.SingleFrameSpansNativeContext && _enablePinning) - { - // Only report no support for by-value contents when element is strictly blittable, such that - // the status remains the same regardless of whether or not runtime marshalling is enabled - if (_elementInfo.MarshallingAttributeInfo is NoMarshallingInfo - || _elementInfo.MarshallingAttributeInfo is UnmanagedBlittableMarshallingInfo { IsStrictlyBlittable: true } - || _elementInfo.MarshallingAttributeInfo is NativeMarshallingAttributeInfo_V1 { IsStrictlyBlittable: true }) - { - return false; - } - } - return marshalKind.HasFlag(ByValueContentsMarshalKind.Out); - } - - public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) - { - if (IsPinningPathSupported(info, context)) - { - return false; - } - return _manualMarshallingGenerator.UsesNativeIdentifier(info, context); - } - - private bool IsPinningPathSupported(TypePositionInfo info, StubCodeContext context) - { - return context.SingleFrameSpansNativeContext && _enablePinning && !info.IsByRef && !info.IsManagedReturnPosition; - } - - private IEnumerable GeneratePinningPath(TypePositionInfo info, StubCodeContext context) - { - (string managedIdentifer, string nativeIdentifier) = context.GetIdentifiers(info); - string byRefIdentifier = $"__byref_{managedIdentifer}"; - - // The element type here is used only for refs/pointers. In the pointer array case, we use byte as the basic placeholder type, - // since we can't use pointer types in generic type parameters. - bool isPointerArray = info.ManagedType is SzArrayType arrayType && arrayType.ElementTypeInfo is PointerTypeInfo; - TypeSyntax arrayElementType = isPointerArray ? PredefinedType(Token(SyntaxKind.ByteKeyword)) : _elementInfo.ManagedType.Syntax; - if (context.CurrentStage == StubCodeContext.Stage.Marshal) - { - // [COMPAT] We use explicit byref calculations here instead of just using a fixed statement - // since a fixed statement converts a zero-length array to a null pointer. - // Many native APIs, such as GDI+, ICU, etc. validate that an array parameter is non-null - // even when the passed in array length is zero. To avoid breaking customers that want to move - // to source-generated interop in subtle ways, we explicitly pass a reference to the 0-th element - // of an array as long as it is non-null, matching the behavior of the built-in interop system - // for single-dimensional zero-based arrays. - - // ref = ref == null ? ref *(*)0 : ref MemoryMarshal.GetArrayDataReference(); - PrefixUnaryExpressionSyntax nullRef = - PrefixUnaryExpression(SyntaxKind.PointerIndirectionExpression, - CastExpression( - PointerType(arrayElementType), - LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0)))); - - InvocationExpressionSyntax getArrayDataReference = - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal), - IdentifierName("GetArrayDataReference")), - ArgumentList(SingletonSeparatedList( - Argument(IdentifierName(managedIdentifer))))); - - yield return LocalDeclarationStatement( - VariableDeclaration( - RefType(arrayElementType)) - .WithVariables(SingletonSeparatedList( - VariableDeclarator(Identifier(byRefIdentifier)) - .WithInitializer(EqualsValueClause( - RefExpression(ParenthesizedExpression( - ConditionalExpression( - BinaryExpression( - SyntaxKind.EqualsExpression, - IdentifierName(managedIdentifer), - LiteralExpression( - SyntaxKind.NullLiteralExpression)), - RefExpression(nullRef), - RefExpression(getArrayDataReference))))))))); - } - if (context.CurrentStage == StubCodeContext.Stage.Pin) - { - // fixed (void* = &) - yield return FixedStatement( - VariableDeclaration( - PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword))), - SingletonSeparatedList( - VariableDeclarator(Identifier(nativeIdentifier)) - .WithInitializer(EqualsValueClause( - PrefixUnaryExpression(SyntaxKind.AddressOfExpression, IdentifierName(byRefIdentifier)))))), - EmptyStatement()); - } - } - } -} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs index a8b4eb3a788fc..100d756bc32e5 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs @@ -299,16 +299,15 @@ private IMarshallingGenerator CreateNativeCollectionMarshaller( // Insert the unmanaged element type into the marshaller type TypeSyntax unmanagedElementType = elementMarshaller.AsNativeType(elementInfo).GetCompatibleGenericTypeParameterSyntax(); TypeSyntax marshallerTypeSyntax = marshallerData.MarshallerType.Syntax; - marshallerTypeSyntax = marshallerTypeSyntax.ReplaceNodes( - marshallerTypeSyntax.DescendantNodesAndSelf().OfType().Where(t => t.IsEquivalentTo(marshalInfo.PlaceholderTypeParameter.Syntax)), - (_, _) => unmanagedElementType); + marshallerTypeSyntax = ReplacePlaceholderSyntaxWithUnmanagedTypeSyntax(marshallerTypeSyntax, marshalInfo, unmanagedElementType); + TypeSyntax nativeTypeSyntax = ReplacePlaceholderSyntaxWithUnmanagedTypeSyntax(marshallerData.NativeType.Syntax, marshalInfo, unmanagedElementType); ICustomTypeMarshallingStrategy marshallingStrategy; bool elementIsBlittable = elementMarshaller is BlittableMarshaller; if (marshallerData.HasState) { - marshallingStrategy = new StatefulValueMarshalling(marshallerTypeSyntax, marshallerData.NativeType.Syntax, marshallerData.Shape); + marshallingStrategy = new StatefulValueMarshalling(marshallerTypeSyntax, nativeTypeSyntax, marshallerData.Shape); if (marshallerData.Shape.HasFlag(MarshallerShape.CallerAllocatedBuffer)) { // Check if the buffer element type is actually the unmanaged element type @@ -331,39 +330,51 @@ private IMarshallingGenerator CreateNativeCollectionMarshaller( { if (elementIsBlittable) { - marshallingStrategy = new StatelessLinearCollectionBlittableElementsMarshalling(marshallerTypeSyntax, marshallerData.NativeType.Syntax, marshallerData.Shape, marshallerData.CollectionElementType.Syntax, unmanagedElementType, numElementsExpression); + marshallingStrategy = new StatelessLinearCollectionBlittableElementsMarshalling(marshallerTypeSyntax, nativeTypeSyntax, marshallerData.Shape, marshallerData.CollectionElementType.Syntax, unmanagedElementType, numElementsExpression); } else { - marshallingStrategy = new StatelessLinearCollectionNonBlittableElementsMarshalling(marshallerTypeSyntax, marshallerData.NativeType.Syntax, marshallerData.Shape, unmanagedElementType, elementMarshaller, elementInfo, numElementsExpression); + marshallingStrategy = new StatelessLinearCollectionNonBlittableElementsMarshalling(marshallerTypeSyntax, nativeTypeSyntax, marshallerData.Shape, unmanagedElementType, elementMarshaller, elementInfo, numElementsExpression); } if (marshallerData.Shape.HasFlag(MarshallerShape.Free)) marshallingStrategy = new StatelessFreeMarshalling(marshallingStrategy, marshallerTypeSyntax); } + IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator( + marshallingStrategy, + enableByValueContentsMarshalling: info.ManagedType is SzArrayType && (!elementIsBlittable || ElementTypeIsSometimesNonBlittable(elementInfo))); - if (marshalInfo.UseDefaultMarshalling && info.ManagedType is SzArrayType) - { - return new ArrayMarshaller( - new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: true), - elementInfo, - elementIsBlittable); - } - - IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false); - - if (marshallerData.Shape.HasFlag(MarshallerShape.StatelessPinnableReference)) + // Elements in the collection must be blittable to use the pinnable marshaller. + if (marshallerData.Shape.HasFlag(MarshallerShape.StatelessPinnableReference) && elementIsBlittable) { marshallingGenerator = new StaticPinnableManagedValueMarshaller(marshallingGenerator, marshallerTypeSyntax); } - // Elements in the collection must be blittable to use the pinnable marshaller. return marshalInfo.IsPinnableManagedType && elementIsBlittable ? new PinnableManagedValueMarshaller(marshallingGenerator) - : marshallingGenerator; + : marshallingGenerator; } + private static bool ElementTypeIsSometimesNonBlittable(TypePositionInfo elementInfo) + { + if (elementInfo.MarshallingAttributeInfo is NoMarshallingInfo + || elementInfo.MarshallingAttributeInfo is UnmanagedBlittableMarshallingInfo { IsStrictlyBlittable: true } + || elementInfo.MarshallingAttributeInfo is NativeMarshallingAttributeInfo_V1 { IsStrictlyBlittable: true }) + { + return false; + } + return true; + } + + private static TypeSyntax ReplacePlaceholderSyntaxWithUnmanagedTypeSyntax( + TypeSyntax originalTypeSyntax, + NativeLinearCollectionMarshallingInfo marshalInfo, + TypeSyntax unmanagedElementType) + => originalTypeSyntax.ReplaceNodes( + originalTypeSyntax.DescendantNodesAndSelf().OfType().Where(t => t.IsEquivalentTo(marshalInfo.PlaceholderTypeParameter.Syntax)), + (_, _) => unmanagedElementType); + private void ValidateCustomNativeTypeMarshallingSupported(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo marshalInfo) { // Marshalling out or return parameter, but no out marshaller is specified @@ -550,14 +561,6 @@ private IMarshallingGenerator CreateNativeCollectionMarshaller_V1( marshallingStrategy, SizeOfExpression(nativeElementType)); - if (collectionInfo.UseDefaultMarshalling && info.ManagedType is SzArrayType) - { - return new ArrayMarshaller( - new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: true), - elementInfo, - elementIsBlittable); - } - IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false); // Elements in the collection must be blittable to use the pinnable marshaller. 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 ffba0c05600f9..26886adb90c01 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 @@ -117,14 +117,21 @@ private static bool TryRehydrateMarshalAsAttribute(TypePositionInfo info, out At { CountInfo countInfo; MarshallingInfo elementMarshallingInfo; - if (info.MarshallingAttributeInfo is NativeLinearCollectionMarshallingInfo_V1 collectionMarshalling - && collectionMarshalling.UseDefaultMarshalling - && collectionMarshalling.ElementCountInfo is NoCountInfo or SizeAndParamIndexInfo - && collectionMarshalling.ElementMarshallingInfo is NoMarshallingInfo or MarshalAsInfo { UnmanagedType: not UnmanagedType.CustomMarshaler } - ) + if (info.MarshallingAttributeInfo is NativeLinearCollectionMarshallingInfo collectionMarshalling + && collectionMarshalling.ElementCountInfo is NoCountInfo or SizeAndParamIndexInfo) { - countInfo = collectionMarshalling.ElementCountInfo; - elementMarshallingInfo = collectionMarshalling.ElementMarshallingInfo; + CustomTypeMarshallerData defaultMarshallerData = collectionMarshalling.Marshallers.GetModeOrDefault(MarshalMode.Default); + if ((defaultMarshallerData.MarshallerType.FullTypeName.StartsWith($"{TypeNames.System_Runtime_InteropServices_ArrayMarshaller}<") + || defaultMarshallerData.MarshallerType.FullTypeName.StartsWith($"{TypeNames.System_Runtime_InteropServices_PointerArrayMarshaller}<")) + && defaultMarshallerData.CollectionElementMarshallingInfo is NoMarshallingInfo or MarshalAsInfo { UnmanagedType: not UnmanagedType.CustomMarshaler }) + { + countInfo = collectionMarshalling.ElementCountInfo; + elementMarshallingInfo = defaultMarshallerData.CollectionElementMarshallingInfo; + } + else + { + return false; + } } else if (info.MarshallingAttributeInfo is MissingSupportCollectionMarshallingInfo missingSupport) { diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs index 6e3a4e1ca789a..b83163809f3b9 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs @@ -153,8 +153,7 @@ public sealed record NativeLinearCollectionMarshallingInfo( CustomTypeMarshallers Marshallers, bool IsPinnableManagedType, CountInfo ElementCountInfo, - ManagedTypeInfo PlaceholderTypeParameter, - bool UseDefaultMarshalling) : NativeMarshallingAttributeInfo( + ManagedTypeInfo PlaceholderTypeParameter) : NativeMarshallingAttributeInfo( EntryPointType, Marshallers, IsPinnableManagedType); @@ -168,7 +167,6 @@ public record NativeMarshallingAttributeInfo_V1( CustomTypeMarshallerDirection Direction, CustomTypeMarshallerFeatures MarshallingFeatures, CustomTypeMarshallerPinning PinningFeatures, - bool UseDefaultMarshalling, bool IsStrictlyBlittable, ManagedTypeInfo? BufferElementType, int? BufferSize) : MarshallingInfo; @@ -188,7 +186,6 @@ public sealed record NativeLinearCollectionMarshallingInfo_V1( CustomTypeMarshallerDirection Direction, CustomTypeMarshallerFeatures MarshallingFeatures, CustomTypeMarshallerPinning PinningFeatures, - bool UseDefaultMarshalling, int? BufferSize, CountInfo ElementCountInfo, ManagedTypeInfo ElementType, @@ -198,7 +195,6 @@ public sealed record NativeLinearCollectionMarshallingInfo_V1( Direction, MarshallingFeatures, PinningFeatures, - UseDefaultMarshalling, IsStrictlyBlittable: false, SpecialTypeInfo.Byte, BufferSize @@ -653,8 +649,7 @@ private MarshallingInfo CreateNativeMarshallingInfo( marshallers.Value, isPinnableManagedType, parsedCountInfo, - ManagedTypeInfo.CreateTypeInfoForTypeSymbol(entryPointType.TypeParameters.Last()), - UseDefaultMarshalling: !isMarshalUsingAttribute); + ManagedTypeInfo.CreateTypeInfoForTypeSymbol(entryPointType.TypeParameters.Last())); } } else @@ -730,7 +725,6 @@ private MarshallingInfo CreateNativeMarshallingInfo_V1( customTypeMarshallerData.Value.Direction, customTypeMarshallerData.Value.Features, pinning, - UseDefaultMarshalling: !isMarshalUsingAttribute, customTypeMarshallerData.Value.BufferSize, parsedCountInfo, ManagedTypeInfo.CreateTypeInfoForTypeSymbol(elementType), @@ -742,8 +736,7 @@ private MarshallingInfo CreateNativeMarshallingInfo_V1( nativeType, attrData, customTypeMarshallerData.Value, - allowPinningManagedType: !isMarshalUsingAttribute, - useDefaultMarshalling: !isMarshalUsingAttribute); + allowPinningManagedType: !isMarshalUsingAttribute); } private MarshallingInfo CreateNativeMarshallingInfoForValue_V1( @@ -751,8 +744,7 @@ private MarshallingInfo CreateNativeMarshallingInfoForValue_V1( INamedTypeSymbol nativeType, AttributeData attrData, CustomTypeMarshallerData_V1 customTypeMarshallerData, - bool allowPinningManagedType, - bool useDefaultMarshalling) + bool allowPinningManagedType) { ManagedTypeInfo? bufferElementTypeInfo = null; if (customTypeMarshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.CallerAllocatedBuffer)) @@ -792,7 +784,6 @@ private MarshallingInfo CreateNativeMarshallingInfoForValue_V1( customTypeMarshallerData.Direction, customTypeMarshallerData.Features, pinning, - useDefaultMarshalling, nativeType.IsStrictlyBlittable(), bufferElementTypeInfo, customTypeMarshallerData.BufferSize); @@ -940,8 +931,7 @@ private MarshallingInfo CreateArrayMarshallingInfo( marshallers.Value, IsPinnableManagedType: false, countInfo, - ManagedTypeInfo.CreateTypeInfoForTypeSymbol(arrayMarshaller.TypeParameters.Last()), - UseDefaultMarshalling: true); + ManagedTypeInfo.CreateTypeInfoForTypeSymbol(arrayMarshaller.TypeParameters.Last())); } } else @@ -967,7 +957,6 @@ private MarshallingInfo CreateArrayMarshallingInfo( Direction: customTypeMarshallerData.Value.Direction, MarshallingFeatures: customTypeMarshallerData.Value.Features, PinningFeatures: CustomTypeMarshallerPinning.NativeType, - UseDefaultMarshalling: true, customTypeMarshallerData.Value.BufferSize, ElementCountInfo: countInfo, ElementType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(elementType), @@ -1020,8 +1009,7 @@ private MarshallingInfo CreateStringMarshallingInfo( stringMarshaller, null, customTypeMarshallerData.Value, - allowPinningManagedType: marshallerName is TypeNames.Utf16StringMarshaller, - useDefaultMarshalling: false); + allowPinningManagedType: marshallerName is TypeNames.Utf16StringMarshaller); } private MarshallingInfo GetBlittableMarshallingInfo(ITypeSymbol type) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs index f0a96eb7c4987..6edf393c32e81 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs @@ -58,9 +58,13 @@ public static string MarshalEx(InteropGenerationOptions options) public const string System_Runtime_InteropServices_MemoryMarshal = "System.Runtime.InteropServices.MemoryMarshal"; - public const string System_Runtime_InteropServices_ArrayMarshaller_Metadata = "System.Runtime.InteropServices.Marshalling.ArrayMarshaller`1"; + public const string System_Runtime_InteropServices_ArrayMarshaller_Metadata = "System.Runtime.InteropServices.Marshalling.ArrayMarshaller`2"; - public const string System_Runtime_InteropServices_PointerArrayMarshaller_Metadata = "System.Runtime.InteropServices.Marshalling.PointerArrayMarshaller`1"; + public const string System_Runtime_InteropServices_PointerArrayMarshaller_Metadata = "System.Runtime.InteropServices.Marshalling.PointerArrayMarshaller`2"; + + public const string System_Runtime_InteropServices_ArrayMarshaller = "System.Runtime.InteropServices.Marshalling.ArrayMarshaller"; + + public const string System_Runtime_InteropServices_PointerArrayMarshaller = "System.Runtime.InteropServices.Marshalling.PointerArrayMarshaller"; public const string System_Runtime_InteropServices_SafeHandle = "System.Runtime.InteropServices.SafeHandle"; diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 3070633841517..24302f90b4698 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2137,26 +2137,38 @@ public void FromNativeValue(byte* value) { } public string? ToManaged() { throw null; } public void FreeNative() { } } - [System.CLSCompliantAttribute(false)] - [System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute(typeof(System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute.GenericPlaceholder[]), - System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerKind.LinearCollection, BufferSize = 0x200, - Features = System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.UnmanagedResources - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.CallerAllocatedBuffer - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.TwoStageMarshalling)] - public unsafe ref struct ArrayMarshaller - { - public ArrayMarshaller(int sizeOfNativeElement) { } - public ArrayMarshaller(T[]? array, int sizeOfNativeElement) { } - public ArrayMarshaller(T[]? array, System.Span buffer, int sizeOfNativeElement) { } - public System.ReadOnlySpan GetManagedValuesSource() { throw null; } - public System.Span GetManagedValuesDestination(int length) { throw null; } - public System.ReadOnlySpan GetNativeValuesSource(int length) { throw null; } - public System.Span GetNativeValuesDestination() { throw null; } - public ref byte GetPinnableReference() { throw null; } - public byte* ToNativeValue() { throw null; } - public void FromNativeValue(byte* value) { } - public T[]? ToManaged() { throw null; } - public void FreeNative() { } + [CLSCompliant(false)] + [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), + MarshalMode.Default, + typeof(ArrayMarshaller<,>))] + [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), + MarshalMode.ManagedToUnmanagedIn, + typeof(ArrayMarshaller<,>.ManagedToUnmanagedIn))] + [ContiguousCollectionMarshaller] + public static unsafe class ArrayMarshaller + where TUnmanagedElement : unmanaged + { + public static byte* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) { throw null; } + public static ReadOnlySpan GetManagedValuesSource(T[]? managed) { throw null; } + public static Span GetUnmanagedValuesDestination(byte* unmanaged, int numElements) { throw null; } + public static T[]? AllocateContainerForManagedElements(byte* unmanaged, int length) { throw null; } + public static Span GetManagedValuesDestination(T[]? managed) { throw null; } + public static ReadOnlySpan GetUnmanagedValuesSource(byte* unmanagedValue, int numElements) { throw null; } + public static void Free(byte* unmanaged) { } + + public unsafe ref struct ManagedToUnmanagedIn + { + public static int BufferSize { get { throw null; } } + public void FromManaged(T[]? array, System.Span buffer) { } + public System.ReadOnlySpan GetManagedValuesSource() { throw null; } + public System.Span GetUnmanagedValuesDestination() { throw null; } + public ref TUnmanagedElement GetPinnableReference() { throw null; } + public static ref T GetPinnableReference(T[]? array) { throw null; } + public TUnmanagedElement* ToUnmanaged() { throw null; } + public void FromUnmanaged(TUnmanagedElement* value) { } + public T[]? ToManaged() { throw null; } + public void Free() { } + } } [System.CLSCompliant(false)] [System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute(typeof(string), BufferSize = 0x100, @@ -2173,6 +2185,11 @@ public void FromNativeValue(void* value) { } public void FreeNative() { } } + [System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class)] + public sealed partial class ContiguousCollectionMarshallerAttribute : System.Attribute + { + } + [System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class, AllowMultiple = true)] public sealed partial class CustomMarshallerAttribute : System.Attribute { @@ -2250,26 +2267,39 @@ public sealed partial class NativeMarshallingAttribute : System.Attribute public NativeMarshallingAttribute(System.Type nativeType) { } public System.Type NativeType { get { throw null; } } } - [System.CLSCompliantAttribute(false)] - [System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute(typeof(System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute.GenericPlaceholder*[]), - System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerKind.LinearCollection, BufferSize = 0x200, - Features = System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.UnmanagedResources - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.CallerAllocatedBuffer - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.TwoStageMarshalling)] - public unsafe ref struct PointerArrayMarshaller where T : unmanaged - { - public PointerArrayMarshaller(int sizeOfNativeElement) { } - public PointerArrayMarshaller(T*[]? array, int sizeOfNativeElement) { } - public PointerArrayMarshaller(T*[]? array, System.Span buffer, int sizeOfNativeElement) { } - public System.ReadOnlySpan GetManagedValuesSource() { throw null; } - public System.Span GetManagedValuesDestination(int length) { throw null; } - public System.ReadOnlySpan GetNativeValuesSource(int length) { throw null; } - public System.Span GetNativeValuesDestination() { throw null; } - public ref byte GetPinnableReference() { throw null; } - public byte* ToNativeValue() { throw null; } - public void FromNativeValue(byte* value) { } - public T*[]? ToManaged() { throw null; } - public void FreeNative() { } + [CLSCompliant(false)] + [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), + MarshalMode.Default, + typeof(PointerArrayMarshaller<,>))] + [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), + MarshalMode.ManagedToUnmanagedIn, + typeof(PointerArrayMarshaller<,>.ManagedToUnmanagedIn))] + [ContiguousCollectionMarshaller] + public static unsafe class PointerArrayMarshaller + where T : unmanaged + where TUnmanagedElement : unmanaged + { + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T*[]? managed, out int numElements) { throw null; } + public static ReadOnlySpan GetManagedValuesSource(T*[]? managed) { throw null; } + public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { throw null; } + public static T*[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int length) { throw null; } + public static Span GetManagedValuesDestination(T*[]? managed) { throw null; } + public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements) { throw null; } + public static void Free(TUnmanagedElement* unmanaged) { } + + public unsafe ref struct ManagedToUnmanagedIn + { + public static int BufferSize { get { throw null; } } + public void FromManaged(T*[]? array, System.Span buffer) { } + public System.ReadOnlySpan GetManagedValuesSource() { throw null; } + public System.Span GetUnmanagedValuesDestination() { throw null; } + public ref TUnmanagedElement GetPinnableReference() { throw null; } + public static ref byte GetPinnableReference(T*[]? array) { throw null; } + public TUnmanagedElement* ToUnmanaged() { throw null; } + public void FromUnmanaged(TUnmanagedElement* value) { } + public T*[]? ToManaged() { throw null; } + public void Free() { } + } } [System.CLSCompliant(false)] [System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute(typeof(string), BufferSize = 0x100, From cabcc428fe47f5485d244e557de44080cbc1f51a Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Jul 2022 15:42:14 -0700 Subject: [PATCH 2/8] cleanup ref assembly attributes --- .../Marshalling/ArrayMarshaller.cs | 4 +-- .../Marshalling/PointerArrayMarshaller.cs | 4 +-- .../ref/System.Runtime.InteropServices.cs | 32 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs index 0f177dc522510..b7c060b67cb8c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs @@ -12,10 +12,10 @@ namespace System.Runtime.InteropServices.Marshalling /// Array element type /// The unmanaged type for the element type [CLSCompliant(false)] - [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), + [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.Default, typeof(ArrayMarshaller<,>))] - [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), + [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(ArrayMarshaller<,>.ManagedToUnmanagedIn))] [ContiguousCollectionMarshaller] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs index e93ca95d5aa2f..730ccd170fead 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs @@ -12,10 +12,10 @@ namespace System.Runtime.InteropServices.Marshalling /// Array element pointer type /// The unmanaged type for the element pointer type [CLSCompliant(false)] - [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), + [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder*[]), MarshalMode.Default, typeof(PointerArrayMarshaller<,>))] - [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), + [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder*[]), MarshalMode.ManagedToUnmanagedIn, typeof(PointerArrayMarshaller<,>.ManagedToUnmanagedIn))] [ContiguousCollectionMarshaller] diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index c06eddc93684e..4983471346737 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2146,14 +2146,14 @@ public ref struct ManagedToUnmanagedIn } } - [CLSCompliant(false)] - [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), - MarshalMode.Default, - typeof(ArrayMarshaller<,>))] - [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder[]), - MarshalMode.ManagedToUnmanagedIn, - typeof(ArrayMarshaller<,>.ManagedToUnmanagedIn))] - [ContiguousCollectionMarshaller] + [System.CLSCompliant(false)] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), + System.Runtime.InteropServices.Marshalling.MarshalMode.Default, + typeof(System.Runtime.InteropServices.Marshalling.ArrayMarshaller<,>))] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), + System.Runtime.InteropServices.Marshalling.MarshalMode.ManagedToUnmanagedIn, + typeof(System.Runtime.InteropServices.Marshalling.ArrayMarshaller<,>.ManagedToUnmanagedIn))] + [System.Runtime.InteropServices.Marshalling.ContiguousCollectionMarshaller] public static unsafe class ArrayMarshaller where TUnmanagedElement : unmanaged { @@ -2283,14 +2283,14 @@ public sealed partial class NativeMarshallingAttribute : System.Attribute public NativeMarshallingAttribute(System.Type nativeType) { } public System.Type NativeType { get { throw null; } } } - [CLSCompliant(false)] - [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), - MarshalMode.Default, - typeof(PointerArrayMarshaller<,>))] - [CustomMarshaller(typeof(CustomTypeMarshallerAttribute.GenericPlaceholder*[]), - MarshalMode.ManagedToUnmanagedIn, - typeof(PointerArrayMarshaller<,>.ManagedToUnmanagedIn))] - [ContiguousCollectionMarshaller] + [System.CLSCompliant(false)] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(CustomMarshallerAttribute.GenericPlaceholder*[]), + System.Runtime.InteropServices.Marshalling.MarshalMode.Default, + typeof(System.Runtime.InteropServices.Marshalling.PointerArrayMarshaller<,>))] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(CustomMarshallerAttribute.GenericPlaceholder*[]), + System.Runtime.InteropServices.Marshalling.MarshalMode.ManagedToUnmanagedIn, + typeof(System.Runtime.InteropServices.Marshalling.PointerArrayMarshaller<,>.ManagedToUnmanagedIn))] + [System.Runtime.InteropServices.Marshalling.ContiguousCollectionMarshaller] public static unsafe class PointerArrayMarshaller where T : unmanaged where TUnmanagedElement : unmanaged From 07ce896ff7a8ab63e46778fbfc1279a6ae6af68b Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Jul 2022 16:15:05 -0700 Subject: [PATCH 3/8] Use TUnmanagedElement* as the unmanaged type for the stateless array marshaller. --- .../InteropServices/Marshalling/ArrayMarshaller.cs | 10 +++++----- .../ref/System.Runtime.InteropServices.cs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs index b7c060b67cb8c..b179ba50fe1fc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs @@ -22,7 +22,7 @@ namespace System.Runtime.InteropServices.Marshalling public static unsafe class ArrayMarshaller where TUnmanagedElement : unmanaged { - public static byte* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) { if (managed is null) { @@ -40,10 +40,10 @@ public static unsafe class ArrayMarshaller public static ReadOnlySpan GetManagedValuesSource(T[]? managed) => managed; - public static Span GetUnmanagedValuesDestination(byte* unmanaged, int numElements) + public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) => new Span(unmanaged, numElements); - public static T[]? AllocateContainerForManagedElements(byte* unmanaged, int length) + public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int length) { if (unmanaged is null) return null; @@ -54,10 +54,10 @@ public static Span GetUnmanagedValuesDestination(byte* unmana public static Span GetManagedValuesDestination(T[]? managed) => managed; - public static ReadOnlySpan GetUnmanagedValuesSource(byte* unmanagedValue, int numElements) + public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements) => new ReadOnlySpan(unmanagedValue, numElements); - public static void Free(byte* unmanaged) + public static void Free(TUnmanagedElement* unmanaged) => Marshal.FreeCoTaskMem((IntPtr)unmanaged); public ref struct ManagedToUnmanagedIn diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 4983471346737..429267ede351b 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2157,13 +2157,13 @@ public ref struct ManagedToUnmanagedIn public static unsafe class ArrayMarshaller where TUnmanagedElement : unmanaged { - public static byte* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) { throw null; } + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) { throw null; } public static ReadOnlySpan GetManagedValuesSource(T[]? managed) { throw null; } - public static Span GetUnmanagedValuesDestination(byte* unmanaged, int numElements) { throw null; } - public static T[]? AllocateContainerForManagedElements(byte* unmanaged, int length) { throw null; } + public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { throw null; } + public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int length) { throw null; } public static Span GetManagedValuesDestination(T[]? managed) { throw null; } - public static ReadOnlySpan GetUnmanagedValuesSource(byte* unmanagedValue, int numElements) { throw null; } - public static void Free(byte* unmanaged) { } + public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements) { throw null; } + public static void Free(TUnmanagedElement* unmanaged) { } public unsafe ref struct ManagedToUnmanagedIn { From 72e9f031c252fbbced5da6e298cf9cddee85b1b4 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Jul 2022 16:17:34 -0700 Subject: [PATCH 4/8] Remove some unused unmanaged->managed direction methods --- .../Marshalling/ArrayMarshaller.cs | 17 +---------------- .../Marshalling/PointerArrayMarshaller.cs | 12 ------------ .../ref/System.Runtime.InteropServices.cs | 4 ---- 3 files changed, 1 insertion(+), 32 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs index b179ba50fe1fc..51c5ec12eb2e2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs @@ -34,7 +34,7 @@ public static unsafe class ArrayMarshaller // Always allocate at least one byte when the array is zero-length. int spaceToAllocate = Math.Max(checked(sizeof(TUnmanagedElement) * numElements), 1); - return (byte*)Marshal.AllocCoTaskMem(spaceToAllocate); + return (TUnmanagedElement*)Marshal.AllocCoTaskMem(spaceToAllocate); } public static ReadOnlySpan GetManagedValuesSource(T[]? managed) @@ -126,21 +126,6 @@ public void FromManaged(T[]? array, Span buffer) /// public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)Unsafe.AsPointer(ref GetPinnableReference()); - /// - /// Sets the unmanaged value representing the array. - /// - /// The unmanaged value. - public void FromUnmanaged(TUnmanagedElement* value) - { - _allocatedMemory = value; - } - - /// - /// Returns the managed array. - /// - /// - public T[]? ToManaged() => _managedArray; - /// /// Frees resources. /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs index 730ccd170fead..fef0d21017bb0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs @@ -126,18 +126,6 @@ public void FromManaged(T*[]? array, Span buffer) /// public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)Unsafe.AsPointer(ref GetPinnableReference()); - /// - /// Sets the unmanaged value representing the array. - /// - /// The unmanaged value. - public void FromUnmanaged(TUnmanagedElement* value) => _allocatedMemory = value; - - /// - /// Returns the managed array. - /// - /// - public T*[]? ToManaged() => _managedArray; - /// /// Frees resources. /// diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 429267ede351b..cf4941594aa75 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2174,8 +2174,6 @@ public void FromManaged(T[]? array, System.Span buffer) { } public ref TUnmanagedElement GetPinnableReference() { throw null; } public static ref T GetPinnableReference(T[]? array) { throw null; } public TUnmanagedElement* ToUnmanaged() { throw null; } - public void FromUnmanaged(TUnmanagedElement* value) { } - public T[]? ToManaged() { throw null; } public void Free() { } } } @@ -2312,8 +2310,6 @@ public void FromManaged(T*[]? array, System.Span buffer) { } public ref TUnmanagedElement GetPinnableReference() { throw null; } public static ref byte GetPinnableReference(T*[]? array) { throw null; } public TUnmanagedElement* ToUnmanaged() { throw null; } - public void FromUnmanaged(TUnmanagedElement* value) { } - public T*[]? ToManaged() { throw null; } public void Free() { } } } From 1a0aa84950e0a268677028c9ca515e1b8ff2edf4 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Jul 2022 16:28:43 -0700 Subject: [PATCH 5/8] Full namespace for Span/ReadOnlySpan in Array/PointerArray marshallers --- .../ref/System.Runtime.InteropServices.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index cf4941594aa75..16ccf97dba6c2 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2158,11 +2158,11 @@ public static unsafe class ArrayMarshaller where TUnmanagedElement : unmanaged { public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) { throw null; } - public static ReadOnlySpan GetManagedValuesSource(T[]? managed) { throw null; } - public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { throw null; } + public static System.ReadOnlySpan GetManagedValuesSource(T[]? managed) { throw null; } + public static System.Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { throw null; } public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int length) { throw null; } - public static Span GetManagedValuesDestination(T[]? managed) { throw null; } - public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements) { throw null; } + public static System.Span GetManagedValuesDestination(T[]? managed) { throw null; } + public static System.ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements) { throw null; } public static void Free(TUnmanagedElement* unmanaged) { } public unsafe ref struct ManagedToUnmanagedIn @@ -2294,11 +2294,11 @@ public static unsafe class PointerArrayMarshaller where TUnmanagedElement : unmanaged { public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T*[]? managed, out int numElements) { throw null; } - public static ReadOnlySpan GetManagedValuesSource(T*[]? managed) { throw null; } - public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { throw null; } + public static System.ReadOnlySpan GetManagedValuesSource(T*[]? managed) { throw null; } + public static System.Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { throw null; } public static T*[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int length) { throw null; } - public static Span GetManagedValuesDestination(T*[]? managed) { throw null; } - public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements) { throw null; } + public static System.Span GetManagedValuesDestination(T*[]? managed) { throw null; } + public static System.ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements) { throw null; } public static void Free(TUnmanagedElement* unmanaged) { } public unsafe ref struct ManagedToUnmanagedIn From 63b2707c011105622dccf9f18f8610eafb6b2466 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Jul 2022 16:37:25 -0700 Subject: [PATCH 6/8] Add dummy fields --- .../ref/System.Runtime.InteropServices.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 16ccf97dba6c2..fc2c193988e5e 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2167,6 +2167,8 @@ public static void Free(TUnmanagedElement* unmanaged) { } public unsafe ref struct ManagedToUnmanagedIn { + private object _dummy; + private int _dummyPrimitive; public static int BufferSize { get { throw null; } } public void FromManaged(T[]? array, System.Span buffer) { } public System.ReadOnlySpan GetManagedValuesSource() { throw null; } @@ -2303,6 +2305,8 @@ public static void Free(TUnmanagedElement* unmanaged) { } public unsafe ref struct ManagedToUnmanagedIn { + private object _dummy; + private int _dummyPrimitive; public static int BufferSize { get { throw null; } } public void FromManaged(T*[]? array, System.Span buffer) { } public System.ReadOnlySpan GetManagedValuesSource() { throw null; } From ccfeae881d9a7abb718046587b9ee6e0d96b779e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Jul 2022 16:58:17 -0700 Subject: [PATCH 7/8] Use numElements instead of length --- .../Runtime/InteropServices/Marshalling/ArrayMarshaller.cs | 4 ++-- .../InteropServices/Marshalling/PointerArrayMarshaller.cs | 4 ++-- .../ref/System.Runtime.InteropServices.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs index 51c5ec12eb2e2..3803812953ca7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ArrayMarshaller.cs @@ -43,12 +43,12 @@ public static ReadOnlySpan GetManagedValuesSource(T[]? managed) public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) => new Span(unmanaged, numElements); - public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int length) + public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) { if (unmanaged is null) return null; - return new T[length]; + return new T[numElements]; } public static Span GetManagedValuesDestination(T[]? managed) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs index fef0d21017bb0..bbfc3baffc423 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs @@ -44,12 +44,12 @@ public static ReadOnlySpan GetManagedValuesSource(T*[]? managed) public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) => new Span(unmanaged, numElements); - public static T*[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int length) + public static T*[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) { if (unmanaged is null) return null; - return new T*[length]; + return new T*[numElements]; } public static Span GetManagedValuesDestination(T*[]? managed) diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index fc2c193988e5e..940490d75dc28 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2160,7 +2160,7 @@ public static unsafe class ArrayMarshaller public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) { throw null; } public static System.ReadOnlySpan GetManagedValuesSource(T[]? managed) { throw null; } public static System.Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { throw null; } - public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int length) { throw null; } + public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) { throw null; } public static System.Span GetManagedValuesDestination(T[]? managed) { throw null; } public static System.ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements) { throw null; } public static void Free(TUnmanagedElement* unmanaged) { } @@ -2298,7 +2298,7 @@ public static unsafe class PointerArrayMarshaller public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T*[]? managed, out int numElements) { throw null; } public static System.ReadOnlySpan GetManagedValuesSource(T*[]? managed) { throw null; } public static System.Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { throw null; } - public static T*[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int length) { throw null; } + public static T*[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) { throw null; } public static System.Span GetManagedValuesDestination(T*[]? managed) { throw null; } public static System.ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanagedValue, int numElements) { throw null; } public static void Free(TUnmanagedElement* unmanaged) { } From 1b64dd0ee99c92ea99bbbec7078e26660a8fff80 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Jul 2022 18:34:35 -0700 Subject: [PATCH 8/8] A few fixes for the collection marshalling strategies that the array marshallers uncovered. --- .../Marshalling/StatefulMarshallingStrategy.cs | 10 ++++++---- .../Marshalling/StatelessMarshallingStrategy.cs | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatefulMarshallingStrategy.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatefulMarshallingStrategy.cs index b5cff6dca7684..e36892f9eb485 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatefulMarshallingStrategy.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatefulMarshallingStrategy.cs @@ -575,7 +575,7 @@ public StatefulLinearCollectionNonBlittableElementsMarshalling( public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context) { - if (!_shape.HasFlag(MarshallerShape.ToUnmanaged)) + if (!_shape.HasFlag(MarshallerShape.ToUnmanaged) && !_shape.HasFlag(MarshallerShape.CallerAllocatedBuffer)) yield break; foreach (StatementSyntax statement in _innerMarshaller.GenerateMarshalStatements(info, context)) @@ -602,9 +602,6 @@ public IEnumerable GenerateMarshalStatements(TypePositionInfo i public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) { - if (!_shape.HasFlag(MarshallerShape.ToManaged)) - yield break; - string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context); if (!info.IsByRef && info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out)) @@ -622,6 +619,11 @@ public IEnumerable GenerateUnmarshalStatements(TypePositionInfo IdentifierName("Length"))))))); yield return GenerateByValueOutUnmarshalStatement(info, context); } + + if (!_shape.HasFlag(MarshallerShape.ToManaged)) + { + yield break; + } else { // int = ; diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatelessMarshallingStrategy.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatelessMarshallingStrategy.cs index 59752b863f231..da467f8a0ee2f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatelessMarshallingStrategy.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StatelessMarshallingStrategy.cs @@ -59,7 +59,7 @@ public IEnumerable GenerateGuaranteedUnmarshalStatements(TypePo public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context) { - if (!_shape.HasFlag(MarshallerShape.ToUnmanaged)) + if (!_shape.HasFlag(MarshallerShape.ToUnmanaged) && !_shape.HasFlag(MarshallerShape.CallerAllocatedBuffer)) yield break; (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); @@ -610,9 +610,6 @@ public IEnumerable GenerateSetupStatements(TypePositionInfo inf public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) { - if (!_shape.HasFlag(MarshallerShape.ToManaged)) - yield break; - (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context); @@ -629,6 +626,11 @@ public IEnumerable GenerateUnmarshalStatements(TypePositionInfo IdentifierName("Length")))); yield return GenerateByValueOutUnmarshalStatement(info, context); } + + if (!_shape.HasFlag(MarshallerShape.ToManaged)) + { + yield break; + } else { // = ;