Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Koritzinsky <jekoritz@microsoft.com>2021-06-09 20:41:29 +0300
committerGitHub <noreply@github.com>2021-06-09 20:41:29 +0300
commita3d954faa056a68deb7620ca99a28514d400337e (patch)
treef60e26b3a165daf50145875479276d4d06113f9b /src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop
parent95552f4b62373528b5bba7c8821990db76beddea (diff)
Implement collection marshaller spec (dotnet/runtimelab#1197)
Commit migrated from https://github.com/dotnet/runtimelab/commit/b3a0ead76a03a92af3b87dd5486563728fb5ecf8
Diffstat (limited to 'src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop')
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ArrayMarshaller.cs217
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedMarshallingAttribute.cs34
2 files changed, 245 insertions, 6 deletions
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ArrayMarshaller.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ArrayMarshaller.cs
new file mode 100644
index 00000000000..370e90efb3d
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ArrayMarshaller.cs
@@ -0,0 +1,217 @@
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices.GeneratedMarshalling
+{
+ public unsafe ref struct ArrayMarshaller<T>
+ {
+ private T[]? managedArray;
+ private readonly int sizeOfNativeElement;
+ private IntPtr allocatedMemory;
+
+ public ArrayMarshaller(int sizeOfNativeElement)
+ :this()
+ {
+ this.sizeOfNativeElement = sizeOfNativeElement;
+ }
+
+ public ArrayMarshaller(T[]? managed, int sizeOfNativeElement)
+ {
+ allocatedMemory = default;
+ this.sizeOfNativeElement = sizeOfNativeElement;
+ if (managed is null)
+ {
+ managedArray = null;
+ NativeValueStorage = default;
+ return;
+ }
+ managedArray = managed;
+ this.sizeOfNativeElement = sizeOfNativeElement;
+ // Always allocate at least one byte when the array is zero-length.
+ int spaceToAllocate = Math.Max(managed.Length * sizeOfNativeElement, 1);
+ allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate);
+ NativeValueStorage = new Span<byte>((void*)allocatedMemory, spaceToAllocate);
+ }
+
+ public ArrayMarshaller(T[]? managed, Span<byte> stackSpace, int sizeOfNativeElement)
+ {
+ allocatedMemory = default;
+ this.sizeOfNativeElement = sizeOfNativeElement;
+ if (managed is null)
+ {
+ managedArray = null;
+ NativeValueStorage = default;
+ return;
+ }
+ managedArray = managed;
+ // Always allocate at least one byte when the array is zero-length.
+ int spaceToAllocate = Math.Max(managed.Length * sizeOfNativeElement, 1);
+ if (spaceToAllocate <= stackSpace.Length)
+ {
+ NativeValueStorage = stackSpace[0..spaceToAllocate];
+ }
+ else
+ {
+ allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate);
+ NativeValueStorage = new Span<byte>((void*)allocatedMemory, spaceToAllocate);
+ }
+ }
+
+ /// <summary>
+ /// Stack-alloc threshold set to 256 bytes to enable small arrays to be passed on the stack.
+ /// Number kept small to ensure that P/Invokes with a lot of array parameters doesn't
+ /// blow the stack since this is a new optimization in the code-generated interop.
+ /// </summary>
+ public const int StackBufferSize = 0x200;
+
+ public Span<T> ManagedValues => managedArray;
+
+ public Span<byte> NativeValueStorage { get; private set; }
+
+ public ref byte GetPinnableReference() => ref MemoryMarshal.GetReference(NativeValueStorage);
+
+ public void SetUnmarshalledCollectionLength(int length)
+ {
+ managedArray = new T[length];
+ }
+
+ public byte* Value
+ {
+ get
+ {
+ Debug.Assert(managedArray is null || allocatedMemory != IntPtr.Zero);
+ return (byte*)allocatedMemory;
+ }
+ set
+ {
+ if (value == null)
+ {
+ managedArray = null;
+ NativeValueStorage = default;
+ }
+ else
+ {
+ allocatedMemory = (IntPtr)value;
+ NativeValueStorage = new Span<byte>(value, (managedArray?.Length ?? 0) * sizeOfNativeElement);
+ }
+ }
+ }
+
+ public T[]? ToManaged() => managedArray;
+
+ public void FreeNative()
+ {
+ if (allocatedMemory != IntPtr.Zero)
+ {
+ Marshal.FreeCoTaskMem(allocatedMemory);
+ }
+ }
+ }
+
+ public unsafe ref struct PtrArrayMarshaller<T> where T : unmanaged
+ {
+ private T*[]? managedArray;
+ private readonly int sizeOfNativeElement;
+ private IntPtr allocatedMemory;
+
+ public PtrArrayMarshaller(int sizeOfNativeElement)
+ : this()
+ {
+ this.sizeOfNativeElement = sizeOfNativeElement;
+ }
+
+ public PtrArrayMarshaller(T*[]? managed, int sizeOfNativeElement)
+ {
+ allocatedMemory = default;
+ this.sizeOfNativeElement = sizeOfNativeElement;
+ if (managed is null)
+ {
+ managedArray = null;
+ NativeValueStorage = default;
+ return;
+ }
+ managedArray = managed;
+ this.sizeOfNativeElement = sizeOfNativeElement;
+ // Always allocate at least one byte when the array is zero-length.
+ int spaceToAllocate = Math.Max(managed.Length * sizeOfNativeElement, 1);
+ allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate);
+ NativeValueStorage = new Span<byte>((void*)allocatedMemory, spaceToAllocate);
+ }
+
+ public PtrArrayMarshaller(T*[]? managed, Span<byte> stackSpace, int sizeOfNativeElement)
+ {
+ allocatedMemory = default;
+ this.sizeOfNativeElement = sizeOfNativeElement;
+ if (managed is null)
+ {
+ managedArray = null;
+ NativeValueStorage = default;
+ return;
+ }
+ managedArray = managed;
+ // Always allocate at least one byte when the array is zero-length.
+ int spaceToAllocate = Math.Max(managed.Length * sizeOfNativeElement, 1);
+ if (spaceToAllocate <= stackSpace.Length)
+ {
+ NativeValueStorage = stackSpace[0..spaceToAllocate];
+ }
+ else
+ {
+ allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate);
+ NativeValueStorage = new Span<byte>((void*)allocatedMemory, spaceToAllocate);
+ }
+ }
+
+ /// <summary>
+ /// Stack-alloc threshold set to 256 bytes to enable small arrays to be passed on the stack.
+ /// Number kept small to ensure that P/Invokes with a lot of array parameters doesn't
+ /// blow the stack since this is a new optimization in the code-generated interop.
+ /// </summary>
+ public const int StackBufferSize = 0x200;
+
+ public Span<IntPtr> ManagedValues => Unsafe.As<IntPtr[]>(managedArray);
+
+ public Span<byte> NativeValueStorage { get; private set; }
+
+ public ref byte GetPinnableReference() => ref MemoryMarshal.GetReference(NativeValueStorage);
+
+ public void SetUnmarshalledCollectionLength(int length)
+ {
+ managedArray = new T*[length];
+ }
+
+ public byte* Value
+ {
+ get
+ {
+ Debug.Assert(managedArray is null || allocatedMemory != IntPtr.Zero);
+ return (byte*)allocatedMemory;
+ }
+ set
+ {
+ if (value == null)
+ {
+ managedArray = null;
+ NativeValueStorage = default;
+ }
+ else
+ {
+ allocatedMemory = (IntPtr)value;
+ NativeValueStorage = new Span<byte>(value, (managedArray?.Length ?? 0) * sizeOfNativeElement);
+ }
+
+ }
+ }
+
+ public T*[]? ToManaged() => managedArray;
+
+ public void FreeNative()
+ {
+ if (allocatedMemory != IntPtr.Zero)
+ {
+ Marshal.FreeCoTaskMem(allocatedMemory);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedMarshallingAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedMarshallingAttribute.cs
index 11e1b29639f..dd605b9e60b 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedMarshallingAttribute.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedMarshallingAttribute.cs
@@ -2,17 +2,17 @@
namespace System.Runtime.InteropServices
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
- class GeneratedMarshallingAttribute : Attribute
+ sealed class GeneratedMarshallingAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Struct)]
- public class BlittableTypeAttribute : Attribute
+ public sealed class BlittableTypeAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
- public class NativeMarshallingAttribute : Attribute
+ public sealed class NativeMarshallingAttribute : Attribute
{
public NativeMarshallingAttribute(Type nativeType)
{
@@ -22,14 +22,36 @@ namespace System.Runtime.InteropServices
public Type NativeType { get; }
}
- [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.Field)]
- public class MarshalUsingAttribute : Attribute
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.Field, AllowMultiple = true)]
+ public sealed class MarshalUsingAttribute : Attribute
{
+ public MarshalUsingAttribute()
+ {
+ CountElementName = string.Empty;
+ }
+
public MarshalUsingAttribute(Type nativeType)
+ :this()
{
NativeType = nativeType;
}
- public Type NativeType { get; }
+ public Type? NativeType { get; }
+
+ public string CountElementName { get; set; }
+
+ public int ConstantElementCount { get; set; }
+
+ public int ElementIndirectionLevel { get; set; }
+
+ public const string ReturnsCountValue = "return-value";
+ }
+
+ [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
+ public sealed class GenericContiguousCollectionMarshallerAttribute : Attribute
+ {
+ public GenericContiguousCollectionMarshallerAttribute()
+ {
+ }
}
} \ No newline at end of file