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 623c28f92bde6..6e86818b1d237 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 @@ -875,6 +875,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..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 @@ -10,147 +10,138 @@ 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(CustomMarshallerAttribute.GenericPlaceholder[]), + MarshalMode.Default, + typeof(ArrayMarshaller<,>))] + [CustomMarshaller(typeof(CustomMarshallerAttribute.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 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 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 (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() => _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(TUnmanagedElement* 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(TUnmanagedElement* unmanaged, int numElements) { - _allocatedMemory = (IntPtr)value; + if (unmanaged is null) + return null; + + return new T[numElements]; } - /// - /// 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(TUnmanagedElement* unmanagedValue, int numElements) + => new ReadOnlySpan(unmanagedValue, numElements); + + public static void Free(TUnmanagedElement* 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()); + + /// + /// 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..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 @@ -10,151 +10,138 @@ 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(CustomMarshallerAttribute.GenericPlaceholder*[]), + MarshalMode.Default, + typeof(PointerArrayMarshaller<,>))] + [CustomMarshaller(typeof(CustomMarshallerAttribute.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 numElements) { - if (_allocatedMemory == IntPtr.Zero) + if (unmanaged is null) return null; - _managedArray = new T*[length]; - return Unsafe.As(_managedArray); + return new T*[numElements]; } - /// - /// 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()); + + /// + /// 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/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 { // = ; 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 84d5720cc3d8f..62977de2de3e4 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 @@ -151,8 +151,7 @@ public sealed record NativeLinearCollectionMarshallingInfo( CustomTypeMarshallers Marshallers, bool IsPinnableManagedType, CountInfo ElementCountInfo, - ManagedTypeInfo PlaceholderTypeParameter, - bool UseDefaultMarshalling) : NativeMarshallingAttributeInfo( + ManagedTypeInfo PlaceholderTypeParameter) : NativeMarshallingAttributeInfo( EntryPointType, Marshallers, IsPinnableManagedType); @@ -166,7 +165,6 @@ public record NativeMarshallingAttributeInfo_V1( CustomTypeMarshallerDirection Direction, CustomTypeMarshallerFeatures MarshallingFeatures, CustomTypeMarshallerPinning PinningFeatures, - bool UseDefaultMarshalling, bool IsStrictlyBlittable, ManagedTypeInfo? BufferElementType, int? BufferSize) : MarshallingInfo; @@ -186,7 +184,6 @@ public sealed record NativeLinearCollectionMarshallingInfo_V1( CustomTypeMarshallerDirection Direction, CustomTypeMarshallerFeatures MarshallingFeatures, CustomTypeMarshallerPinning PinningFeatures, - bool UseDefaultMarshalling, int? BufferSize, CountInfo ElementCountInfo, ManagedTypeInfo ElementType, @@ -196,7 +193,6 @@ public sealed record NativeLinearCollectionMarshallingInfo_V1( Direction, MarshallingFeatures, PinningFeatures, - UseDefaultMarshalling, IsStrictlyBlittable: false, SpecialTypeInfo.Byte, BufferSize @@ -651,8 +647,7 @@ private MarshallingInfo CreateNativeMarshallingInfo( marshallers.Value, isPinnableManagedType, parsedCountInfo, - ManagedTypeInfo.CreateTypeInfoForTypeSymbol(entryPointType.TypeParameters.Last()), - UseDefaultMarshalling: !isMarshalUsingAttribute); + ManagedTypeInfo.CreateTypeInfoForTypeSymbol(entryPointType.TypeParameters.Last())); } } else @@ -728,7 +723,6 @@ private MarshallingInfo CreateNativeMarshallingInfo_V1( customTypeMarshallerData.Value.Direction, customTypeMarshallerData.Value.Features, pinning, - UseDefaultMarshalling: !isMarshalUsingAttribute, customTypeMarshallerData.Value.BufferSize, parsedCountInfo, ManagedTypeInfo.CreateTypeInfoForTypeSymbol(elementType), @@ -740,8 +734,7 @@ private MarshallingInfo CreateNativeMarshallingInfo_V1( nativeType, attrData, customTypeMarshallerData.Value, - allowPinningManagedType: !isMarshalUsingAttribute, - useDefaultMarshalling: !isMarshalUsingAttribute); + allowPinningManagedType: !isMarshalUsingAttribute); } private MarshallingInfo CreateNativeMarshallingInfoForValue_V1( @@ -749,8 +742,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)) @@ -790,7 +782,6 @@ private MarshallingInfo CreateNativeMarshallingInfoForValue_V1( customTypeMarshallerData.Direction, customTypeMarshallerData.Features, pinning, - useDefaultMarshalling, nativeType.IsStrictlyBlittable(), bufferElementTypeInfo, customTypeMarshallerData.BufferSize); @@ -938,8 +929,7 @@ private MarshallingInfo CreateArrayMarshallingInfo( marshallers.Value, IsPinnableManagedType: false, countInfo, - ManagedTypeInfo.CreateTypeInfoForTypeSymbol(arrayMarshaller.TypeParameters.Last()), - UseDefaultMarshalling: true); + ManagedTypeInfo.CreateTypeInfoForTypeSymbol(arrayMarshaller.TypeParameters.Last())); } } else @@ -965,7 +955,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), @@ -1018,8 +1007,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 8021a9d5f09d3..940490d75dc28 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2145,26 +2145,39 @@ public ref struct ManagedToUnmanagedIn public void Free() { 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 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() { } + + [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 + { + 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 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 + { + 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; } + 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 Free() { } + } } [System.CLSCompliant(false)] [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(string), @@ -2187,6 +2200,12 @@ public ref struct ManagedToUnmanagedIn public void Free() { throw null; } } } + + [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 { @@ -2264,26 +2283,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() { } + [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 + { + 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 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 + { + 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; } + 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 Free() { } + } } [System.CLSCompliant(false)] [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(string),