From: Sergio Pedri Date: Fri, 28 Apr 2023 16:38:49 +0000 (-0700) Subject: Add ImmutableCollectionsMarshal type and AsImmutableArray/AsArray APIs (#85526) X-Git-Tag: accepted/tizen/unified/riscv/20231226.055536~2569 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f1c9771a9b8a9cf40e0cca6163a2706bcb6dc033;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Add ImmutableCollectionsMarshal type and AsImmutableArray/AsArray APIs (#85526) * Add ImmutableCollectionsMarshal type * Add ImmutableCollectionsMarshal to ref assembly * Add ImmutableCollectionsMarshal unit tests * Use ImmutableCollectionsMarshal in System.Reflection.Metadata * Remove ImmutableArrayFactory and use new API * Leverage internal members in ImmutableCollectionsMarshal * Remove leftover unsafe modifier in ImmutableCollectionsMarshal --- diff --git a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs index bb9e96e..aef043f 100644 --- a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs +++ b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs @@ -1257,3 +1257,11 @@ namespace System.Linq public static System.Collections.Generic.IEnumerable Where(this System.Collections.Immutable.ImmutableArray immutableArray, System.Func predicate) { throw null; } } } +namespace System.Runtime.InteropServices +{ + public static partial class ImmutableCollectionsMarshal + { + public static System.Collections.Immutable.ImmutableArray AsImmutableArray(T[]? array) { throw null; } + public static T[]? AsArray(System.Collections.Immutable.ImmutableArray array) { throw null; } + } +} diff --git a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj index 64b075b..8ec05a3 100644 --- a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj +++ b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj @@ -24,7 +24,6 @@ The System.Collections.Immutable library is built-in as part of the shared frame - @@ -141,6 +140,7 @@ The System.Collections.Immutable library is built-in as part of the shared frame + diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenDictionary.cs index a1e5016..607284e 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenDictionary.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace System.Collections.Frozen { @@ -338,7 +339,7 @@ namespace System.Collections.Frozen /// /// The order of the keys in the dictionary is unspecified, but it is the same order as the associated values returned by the property. /// - public ImmutableArray Keys => ImmutableArrayFactory.Create(KeysCore); + public ImmutableArray Keys => ImmutableCollectionsMarshal.AsImmutableArray(KeysCore); /// private protected abstract TKey[] KeysCore { get; } @@ -360,7 +361,7 @@ namespace System.Collections.Frozen /// /// The order of the values in the dictionary is unspecified, but it is the same order as the associated keys returned by the property. /// - public ImmutableArray Values => ImmutableArrayFactory.Create(ValuesCore); + public ImmutableArray Values => ImmutableCollectionsMarshal.AsImmutableArray(ValuesCore); /// private protected abstract TValue[] ValuesCore { get; } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs index df86732..7237e79 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSet.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; +using System.Runtime.InteropServices; namespace System.Collections.Frozen { @@ -274,7 +275,7 @@ namespace System.Collections.Frozen /// Gets a collection containing the values in the set. /// The order of the values in the set is unspecified. - public ImmutableArray Items => ImmutableArrayFactory.Create(ItemsCore); + public ImmutableArray Items => ImmutableCollectionsMarshal.AsImmutableArray(ItemsCore); /// private protected abstract T[] ItemsCore { get; } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ImmutableArrayFactory.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ImmutableArrayFactory.cs deleted file mode 100644 index a1ad3b2..0000000 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/ImmutableArrayFactory.cs +++ /dev/null @@ -1,19 +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.Collections.Immutable; - -namespace System.Collections.Frozen -{ - /// - /// Stubs to isolate the frozen collection code from the internal details of ImmutableArray - /// - /// - /// This is intended to make it easier to use the frozen collections in environments/conditions - /// when only the public API of ImmutableArray is available. - /// - internal static class ImmutableArrayFactory - { - public static ImmutableArray Create(T[] array) => new ImmutableArray(array); - } -} diff --git a/src/libraries/System.Collections.Immutable/src/System/Runtime.InteropServices/ImmutableCollectionsMarshal.cs b/src/libraries/System.Collections.Immutable/src/System/Runtime.InteropServices/ImmutableCollectionsMarshal.cs new file mode 100644 index 0000000..737a3a8 --- /dev/null +++ b/src/libraries/System.Collections.Immutable/src/System/Runtime.InteropServices/ImmutableCollectionsMarshal.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Immutable; + +namespace System.Runtime.InteropServices +{ + /// + /// An unsafe class that provides a set of methods to access the underlying data representations of immutable collections. + /// + public static class ImmutableCollectionsMarshal + { + /// + /// Gets an value wrapping the input array. + /// + /// The type of elements in the input array. + /// The input array to wrap in the returned value. + /// An value wrapping . + /// + /// + /// When using this method, callers should take extra care to ensure that they're the sole owners of the input + /// array, and that it won't be modified once the returned value starts being + /// used. Doing so might cause undefined behavior in code paths which don't expect the contents of a given + /// values to change after its creation. + /// + /// + /// If is , the returned value + /// will be uninitialized (ie. its property will be ). + /// + /// + public static ImmutableArray AsImmutableArray(T[]? array) + { + return new(array); + } + + /// + /// Gets the underlying array for an input value. + /// + /// The type of elements in the input value. + /// The input value to get the underlying array from. + /// The underlying array for , if present. + /// + /// + /// When using this method, callers should make sure to not pass the resulting underlying array to methods that + /// might mutate it. Doing so might cause undefined behavior in code paths using which + /// don't expect the contents of the value to change. + /// + /// + /// If is uninitialized (ie. its property is + /// ), the resulting array will be . + /// + /// + public static T[]? AsArray(ImmutableArray array) + { + return array.array; + } + } +} diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableCollectionsMarshal.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableCollectionsMarshal.cs new file mode 100644 index 0000000..76ed476 --- /dev/null +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableCollectionsMarshal.cs @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +namespace System.Collections.Immutable.Tests +{ + public class ImmutableCollectionsMarshalTest + { + [Fact] + public void AsImmutableArrayFromNullArray() + { + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(null).IsDefault); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(null).IsDefault); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(null).IsDefault); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(null).IsDefault); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(null).IsDefault); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(null).IsDefault); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(null).IsDefault); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(null).IsDefault); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(null).IsDefault); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(null).IsDefault); + } + + [Fact] + public void AsImmutableArrayFromEmptyArray() + { + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(Array.Empty()).IsEmpty); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(Array.Empty()).IsEmpty); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(Array.Empty()).IsEmpty); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(Array.Empty()).IsEmpty); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(Array.Empty()).IsEmpty); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(Array.Empty()).IsEmpty); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(Array.Empty()).IsEmpty); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(Array.Empty()).IsEmpty); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(Array.Empty()).IsEmpty); + Assert.True(ImmutableCollectionsMarshal.AsImmutableArray(Array.Empty()).IsEmpty); + } + + [Fact] + public void AsImmutableArrayFromExistingArray() + { + static void Test() + { + T[] array = new T[17]; + ImmutableArray immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(array); + + Assert.False(immutableArray.IsDefault); + Assert.Equal(17, immutableArray.Length); + + ref T expectedRef = ref array[0]; + ref T actualRef = ref Unsafe.AsRef(in immutableArray.ItemRef(0)); + + Assert.True(Unsafe.AreSame(ref expectedRef, ref actualRef)); + } + + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + } + + [Fact] + public void AsArrayFromDefaultImmutableArray() + { + Assert.Null(ImmutableCollectionsMarshal.AsArray(default)); + Assert.Null(ImmutableCollectionsMarshal.AsArray(default)); + Assert.Null(ImmutableCollectionsMarshal.AsArray(default)); + Assert.Null(ImmutableCollectionsMarshal.AsArray(default)); + Assert.Null(ImmutableCollectionsMarshal.AsArray(default)); + Assert.Null(ImmutableCollectionsMarshal.AsArray(default)); + Assert.Null(ImmutableCollectionsMarshal.AsArray(default)); + Assert.Null(ImmutableCollectionsMarshal.AsArray(default)); + Assert.Null(ImmutableCollectionsMarshal.AsArray(default)); + Assert.Null(ImmutableCollectionsMarshal.AsArray(default)); + } + + [Fact] + public void AsArrayFromEmptyImmutableArray() + { + static void Test() + { + T[]? array = ImmutableCollectionsMarshal.AsArray(ImmutableArray.Empty); + + Assert.NotNull(array); + Assert.Empty(array); + } + + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + } + + [Fact] + public void AsArrayFromConstructedImmutableArray() + { + static void Test() + { + ImmutableArray immutableArray = ImmutableArray.Create(new T[17]); + T[]? array = ImmutableCollectionsMarshal.AsArray(immutableArray); + + Assert.NotNull(array); + Assert.Equal(17, array.Length); + + ref T expectedRef = ref Unsafe.AsRef(in immutableArray.ItemRef(0)); + ref T actualRef = ref array[0]; + + Assert.True(Unsafe.AreSame(ref expectedRef, ref actualRef)); + } + + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + Test(); + } + + public class CustomClass + { + public object Foo; + public Guid Bar; + } + + public struct ManagedCustomStruct + { + public object Foo; + public Guid Bar; + } + + public struct UnmanagedCustomStruct + { + public Guid Foo; + public int Bar; + } + } +} diff --git a/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj b/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj index dfc053e..307c682 100644 --- a/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj +++ b/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj @@ -21,6 +21,7 @@ + diff --git a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj index ad67c99..d241f17 100644 --- a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj +++ b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj @@ -110,7 +110,6 @@ The System.Reflection.Metadata library is built-in as part of the shared framewo - diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/ByteArrayMemoryProvider.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/ByteArrayMemoryProvider.cs index fae4a71..040baf7 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/ByteArrayMemoryProvider.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/ByteArrayMemoryProvider.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.IO; +using System.Runtime.InteropServices; using System.Threading; namespace System.Reflection.Internal @@ -45,7 +46,7 @@ namespace System.Reflection.Internal { if (_pinned == null) { - var newPinned = new PinnedObject(ImmutableByteArrayInterop.DangerousGetUnderlyingArray(_array)!); + var newPinned = new PinnedObject(ImmutableCollectionsMarshal.AsArray(_array)!); if (Interlocked.CompareExchange(ref _pinned, newPinned, null) != null) { diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ImmutableByteArrayInterop.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ImmutableByteArrayInterop.cs deleted file mode 100644 index 0621334..0000000 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ImmutableByteArrayInterop.cs +++ /dev/null @@ -1,80 +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.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - -namespace System.Reflection.Internal -{ - /// - /// Provides tools for using in interop scenarios. - /// - /// - /// *** WARNING *** - /// - /// If you decide to copy this code elsewhere, please retain the documentation here - /// and the Dangerous prefixes in the API names. This will help track down and audit - /// other places where this technique (with dangerous consequences when misused) may - /// be applied. - /// - /// A generic version of this API was once public in a pre-release of immutable - /// collections, but it was deemed to be too subject to abuse when available publicly. - /// - /// This implementation is scoped to byte arrays as that is all that the metadata reader needs. - /// - /// Also, since we don't have access to immutable collection internals, we use - /// . - /// - /// The fact that is backed by a single byte array - /// field is something inherent to the design of ImmutableArray in order to get its performance - /// characteristics and therefore something we (Microsoft) are comfortable defining as a contract that - /// can be depended upon as below. - /// - internal static unsafe class ImmutableByteArrayInterop - { - /// - /// Creates a new instance of using a given mutable array as the backing - /// field, without creating a defensive copy. It is the responsibility of the caller to ensure no other mutable - /// references exist to the array. Do not mutate the array after calling this method. - /// - /// The mutable array to use as the backing field. The incoming reference is set to null - /// since it should not be retained by the caller. - /// - /// Users of this method should take extra care to ensure that the mutable array given as a parameter - /// is never modified. The returned will use the given array as its backing - /// field without creating a defensive copy, so changes made to the given mutable array will be observable - /// on the returned . Instance and static methods of - /// and may malfunction if they operate on an instance - /// whose underlying backing field is modified. - /// - /// An immutable array. - internal static ImmutableArray DangerousCreateFromUnderlyingArray(ref byte[]? array) - { - byte[] givenArray = array!; - array = null; - - return Unsafe.As>(ref givenArray); - } - - /// - /// Access the backing mutable array instance for the given , without - /// creating a defensive copy. It is the responsibility of the caller to ensure the array is not modified - /// through the returned mutable reference. Do not mutate the returned array. - /// - /// The from which to retrieve the backing field. - /// - /// Users of this method should take extra care to ensure that the returned mutable array is never modified. - /// The returned mutable array continues to be used as the backing field of the given - /// without creating a defensive copy, so changes made to the returned mutable array will be observable - /// on the given . Instance and static methods of - /// and may malfunction if they operate on an instance - /// whose underlying backing field is modified. - /// - /// The underlying array, or null if is true. - internal static byte[]? DangerousGetUnderlyingArray(ImmutableArray array) - { - return Unsafe.As, byte[]>(ref array); - } - } -} diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs index 98bda9e..9804b82 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs @@ -316,7 +316,7 @@ namespace System.Reflection.Metadata public ImmutableArray ToImmutableArray(int start, int byteCount) { byte[]? array = ToArray(start, byteCount); - return ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref array); + return ImmutableCollectionsMarshal.AsImmutableArray(array); } internal bool TryGetSpan(out ReadOnlySpan buffer) diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs index 6e12e43..6085b95 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs @@ -72,7 +72,7 @@ namespace System.Reflection.Metadata public ImmutableArray GetILContent() { byte[]? bytes = GetILBytes(); - return ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref bytes); + return ImmutableCollectionsMarshal.AsImmutableArray(bytes); } public BlobReader GetILReader() diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs index 89a221b..a275a9b 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Reflection.Internal; using System.Reflection.Metadata.Ecma335; +using System.Runtime.InteropServices; using System.Text; namespace System.Reflection.Metadata @@ -551,7 +552,7 @@ namespace System.Reflection.Metadata externalTableRowCounts = ReadMetadataTableRowCounts(ref reader, externalTableMask); debugMetadataHeader = new DebugMetadataHeader( - ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref pdbId), + ImmutableCollectionsMarshal.AsImmutableArray(pdbId), MethodDefinitionHandle.FromRowId(entryPointRowId), idStartOffset: pdbStreamOffset); } @@ -1081,7 +1082,7 @@ namespace System.Reflection.Metadata { // TODO: We can skip a copy for virtual blobs. byte[]? bytes = GetBlobBytes(handle); - return ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref bytes); + return ImmutableCollectionsMarshal.AsImmutableArray(bytes); } public BlobReader GetBlobReader(BlobHandle handle) diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs index d2e1083..042d9f9 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs @@ -7,6 +7,7 @@ using System.IO; using System.Reflection.Internal; using System.Reflection.Metadata; using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; using System.Threading; using ImmutableArrayExtensions = System.Linq.ImmutableArrayExtensions; @@ -659,7 +660,7 @@ namespace System.Reflection.PortableExecutable return new PdbChecksumDebugDirectoryData( algorithmName, - ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref checksum)); + ImmutableCollectionsMarshal.AsImmutableArray(checksum)); } /// diff --git a/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj b/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj index c946c2e..60644e4 100644 --- a/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj +++ b/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj @@ -87,7 +87,6 @@ - diff --git a/src/libraries/System.Reflection.Metadata/tests/TestUtilities/PinnedBlob.cs b/src/libraries/System.Reflection.Metadata/tests/TestUtilities/PinnedBlob.cs index 4fec831..6ac9f8b 100644 --- a/src/libraries/System.Reflection.Metadata/tests/TestUtilities/PinnedBlob.cs +++ b/src/libraries/System.Reflection.Metadata/tests/TestUtilities/PinnedBlob.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; -using System.Reflection.Internal; using System.Runtime.InteropServices; namespace System.Reflection.Metadata.Tests @@ -13,7 +12,7 @@ namespace System.Reflection.Metadata.Tests private readonly byte[] _blob; public PinnedBlob(ImmutableArray blob) - : this(ImmutableByteArrayInterop.DangerousGetUnderlyingArray(blob)) + : this(ImmutableCollectionsMarshal.AsArray(blob)) { } diff --git a/src/libraries/System.Reflection.Metadata/tests/Utilities/ImmutableByteArrayInteropTest.cs b/src/libraries/System.Reflection.Metadata/tests/Utilities/ImmutableByteArrayInteropTest.cs deleted file mode 100644 index 63b360b..0000000 --- a/src/libraries/System.Reflection.Metadata/tests/Utilities/ImmutableByteArrayInteropTest.cs +++ /dev/null @@ -1,66 +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.Collections.Immutable; -using System.Reflection.Internal; -using Xunit; - -namespace System.Reflection.Metadata.Tests -{ - public class ImmutableByteArrayInteropTest - { - [Fact] - public void DangerousCreateFromUnderlyingArray() - { - byte[] array = new byte[3] { 1, 2, 3 }; - byte[] arrayCopy = array; - ImmutableArray immutable = ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref array); - - // DangerousCreateFromUnderlyingArray clears the given parameter as a signal that - // the mutable array should no longer be modified through mutable references. - Assert.Null(array); - - Assert.Equal(3, immutable.Length); - Assert.Equal(1, immutable[0]); - Assert.Equal(2, immutable[1]); - Assert.Equal(3, immutable[2]); - - arrayCopy[0] = 9; - - Assert.Equal(9, immutable[0]); - } - - [Fact] - public void DangerousCreateFromUnderlyingArrayNegativeTests() - { - byte[] array = null; - ImmutableArray immutable = ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref array); - - Assert.True(immutable.IsDefault); - } - - [Fact] - public void DangerousGetUnderlyingArray() - { - ImmutableArray immutable = ImmutableArray.Create(1, 2, 3); - byte[] array = ImmutableByteArrayInterop.DangerousGetUnderlyingArray(immutable); - - Assert.Equal(3, array.Length); - Assert.Equal(1, array[0]); - Assert.Equal(2, array[1]); - Assert.Equal(3, array[2]); - - array[0] = 9; - - Assert.Equal(9, immutable[0]); - } - - [Fact] - public void DangerousGetUnderlyingArrayNegativeTests() - { - ImmutableArray immutable = default(ImmutableArray); - - Assert.Null(ImmutableByteArrayInterop.DangerousGetUnderlyingArray(immutable)); - } - } -}