From: dotnet bot Date: Thu, 18 Jan 2018 23:36:01 +0000 (-0800) Subject: Mirror changes from dotnet/corefx (#15909) X-Git-Tag: accepted/tizen/base/20180629.140029~112 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d44f3e883a803b2d1fe4fb2c07f92d78bff56eed;p=platform%2Fupstream%2Fcoreclr.git Mirror changes from dotnet/corefx (#15909) * Consolidate System.Memory code to shared folder (dotnet/corefx#26393) * Consolidate System.Memory code to shared folder This change is removing the duplicate codes from System.Memory and keep only one copy under the shared folder to be easier to edit such code in one place and get reflected on the other repos. * Address the review feedback * Addressing more feedback * More cleanup * remove empty line and added a comment Signed-off-by: dotnet-bot-corefx-mirror * Add missing throw helper methods used in the code we got from corefx * Update the exception helper * fix the break --- diff --git a/src/mscorlib/Resources/Strings.resx b/src/mscorlib/Resources/Strings.resx index 19d81b1..84679de 100644 --- a/src/mscorlib/Resources/Strings.resx +++ b/src/mscorlib/Resources/Strings.resx @@ -1,17 +1,17 @@  - @@ -2866,6 +2866,9 @@ Marshaler restriction: Excessively long string. + + Memory<T> has been disposed. + Constructor on type '{0}' not found. diff --git a/src/mscorlib/shared/System/Buffers/IRetainable.cs b/src/mscorlib/shared/System/Buffers/IRetainable.cs index 8d71fc6..6ac5088 100644 --- a/src/mscorlib/shared/System/Buffers/IRetainable.cs +++ b/src/mscorlib/shared/System/Buffers/IRetainable.cs @@ -7,9 +7,20 @@ using System.Runtime.CompilerServices; namespace System.Buffers { + /// + /// Provides a mechanism for manual lifetime management. + /// public interface IRetainable { + /// + /// Call this method to indicate that the IRetainable object is in use. + /// Do not dispose until Release is called. + /// void Retain(); + /// + /// Call this method to indicate that the IRetainable object is no longer in use. + /// The object can now be disposed. + /// bool Release(); } } \ No newline at end of file diff --git a/src/mscorlib/shared/System/Buffers/MemoryHandle.cs b/src/mscorlib/shared/System/Buffers/MemoryHandle.cs index 6059214..01f9563 100644 --- a/src/mscorlib/shared/System/Buffers/MemoryHandle.cs +++ b/src/mscorlib/shared/System/Buffers/MemoryHandle.cs @@ -7,20 +7,46 @@ using System.Runtime.InteropServices; namespace System.Buffers { + /// + /// A handle for the memory. + /// public unsafe struct MemoryHandle : IDisposable { - private IRetainable _owner; + private IRetainable _retainable; private void* _pointer; private GCHandle _handle; + /// + /// Creates a new memory handle for the memory. + /// + /// reference to manually managed object + /// pointer to memory, or null if a pointer was not provided when the handle was created + /// handle used to pin array buffers [CLSCompliant(false)] - public MemoryHandle(IRetainable owner, void* pointer = null, GCHandle handle = default(GCHandle)) + public MemoryHandle(IRetainable retainable, void* pointer = null, GCHandle handle = default(GCHandle)) { - _owner = owner; + _retainable = retainable; _pointer = pointer; _handle = handle; } + /// + /// Returns the pointer to memory, or null if a pointer was not provided when the handle was created. + /// + [CLSCompliant(false)] + public void* Pointer => _pointer; + + /// + /// Returns false if the pointer to memory is null. + /// + public bool HasPointer => _pointer != null; + + /// + /// Adds an offset to the pinned pointer. + /// + /// + /// Throw when pinned pointer is null. + /// internal void AddOffset(int offset) { if (_pointer == null) @@ -33,26 +59,24 @@ namespace System.Buffers } } - [CLSCompliant(false)] - public void* Pointer => _pointer; - - public bool HasPointer => _pointer != null; - - public void Dispose() - { - if (_handle.IsAllocated) + /// + /// Frees the pinned handle and releases IRetainable. + /// + public void Dispose() + { + if (_handle.IsAllocated) { _handle.Free(); } - if (_owner != null) + if (_retainable != null) { - _owner.Release(); - _owner = null; + _retainable.Release(); + _retainable = null; } - _pointer = null; + _pointer = null; } - + } } \ No newline at end of file diff --git a/src/mscorlib/shared/System/Buffers/OwnedMemory.cs b/src/mscorlib/shared/System/Buffers/OwnedMemory.cs index 1167670..bbde61b 100644 --- a/src/mscorlib/shared/System/Buffers/OwnedMemory.cs +++ b/src/mscorlib/shared/System/Buffers/OwnedMemory.cs @@ -7,46 +7,88 @@ using System.Runtime.CompilerServices; namespace System.Buffers { + /// + /// Owner of Memory that provides appropriate lifetime management mechanisms for it. + /// public abstract class OwnedMemory : IDisposable, IRetainable { + /// + /// The number of items in the Memory. + /// public abstract int Length { get; } + /// + /// Returns a span wrapping the underlying memory. + /// public abstract Span Span { get; } + /// + /// Returns a Memory if the underlying memory has not been freed. + /// + /// + /// Thrown when the underlying memory has already been disposed. + /// public Memory Memory { - get + get { - if (IsDisposed) + if (IsDisposed) { - ThrowHelper.ThrowObjectDisposedException(nameof(OwnedMemory), ExceptionResource.Memory_ThrowIfDisposed); + ThrowHelper.ThrowObjectDisposedException_MemoryDisposed(); } return new Memory(owner: this, 0, Length); } } + /// + /// Returns a handle for the array that has been pinned and hence its address can be taken + /// public abstract MemoryHandle Pin(); + /// + /// Returns an array segment. + /// protected internal abstract bool TryGetArray(out ArraySegment arraySegment); + /// + /// Implements IDisposable. + /// + /// + /// Throw when there are still retained references to the memory + /// public void Dispose() { - if (IsRetained) + if (IsRetained) { - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Memory_OutstandingReferences); + ThrowHelper.ThrowInvalidOperationException_OutstandingReferences(); } Dispose(true); GC.SuppressFinalize(this); } + /// + /// Clean up of any leftover managed and unmanaged resources. + /// protected abstract void Dispose(bool disposing); + /// + /// Return true if someone is holding a reference to the memory. + /// protected abstract bool IsRetained { get; } + /// + /// Return true if the underlying memory has been freed. + /// public abstract bool IsDisposed { get; } + /// + /// Implements IRetainable. Prevent accidental disposal of the memory. + /// public abstract void Retain(); + /// + /// Implements IRetainable. The memory can now be diposed. + /// public abstract bool Release(); } diff --git a/src/mscorlib/shared/System/Memory.cs b/src/mscorlib/shared/System/Memory.cs index 2286d69..9cb6e38 100644 --- a/src/mscorlib/shared/System/Memory.cs +++ b/src/mscorlib/shared/System/Memory.cs @@ -8,10 +8,16 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; +#if !FEATURE_PORTABLE_SPAN using Internal.Runtime.CompilerServices; +#endif // FEATURE_PORTABLE_SPAN namespace System { + /// + /// Memory represents a contiguous region of arbitrary memory similar to . + /// Unlike , it is not a byref-like type. + /// [DebuggerDisplay("{DebuggerDisplay,nq}")] [DebuggerTypeProxy(typeof(MemoryDebugView<>))] public readonly struct Memory @@ -77,16 +83,12 @@ namespace System _index = start; _length = length; } - + // Constructor for internal use only. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Memory(OwnedMemory owner, int index, int length) { - if (owner == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.ownedMemory); - if (index < 0 || length < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(); - + // No validation performed; caller must provide any necessary validation. _object = owner; _index = index | (1 << 31); // Before using _index, check if _index < 0, then 'and' it with RemoveOwnedFlagBitMask _length = length; @@ -105,7 +107,7 @@ namespace System /// Defines an implicit conversion of an array to a /// public static implicit operator Memory(T[] array) => new Memory(array); - + /// /// Defines an implicit conversion of a to a /// @@ -168,7 +170,7 @@ namespace System { ThrowHelper.ThrowArgumentOutOfRangeException(); } - + return new Memory(_object, _index + start, length); } @@ -191,7 +193,11 @@ namespace System // and then cast to a Memory. Such a cast can only be done with unsafe or marshaling code, // in which case that's the dangerous operation performed by the dev, and we're just following // suit here to make it work as best as possible. +#if FEATURE_PORTABLE_SPAN + return new Span(Unsafe.As>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length); +#else return new Span(ref Unsafe.As(ref s.GetRawStringData()), s.Length).Slice(_index, _length); +#endif // FEATURE_PORTABLE_SPAN } else if (_object != null) { @@ -227,6 +233,10 @@ namespace System /// The span to copy items into. public bool TryCopyTo(Memory destination) => Span.TryCopyTo(destination.Span); + /// + /// Returns a handle for the array. + /// If pin is true, the GC will not move the array and hence its address can be taken + /// public unsafe MemoryHandle Retain(bool pin = false) { MemoryHandle memoryHandle = default; @@ -245,13 +255,21 @@ namespace System // a readable ReadOnlyMemory or a writable Memory can still be pinned and // used for interop purposes. GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned); +#if FEATURE_PORTABLE_SPAN + void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); +#else void* pointer = Unsafe.Add(Unsafe.AsPointer(ref s.GetRawStringData()), _index); +#endif // FEATURE_PORTABLE_SPAN memoryHandle = new MemoryHandle(null, pointer, handle); } else if (_object is T[] array) { var handle = GCHandle.Alloc(array, GCHandleType.Pinned); +#if FEATURE_PORTABLE_SPAN + void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); +#else void* pointer = Unsafe.Add(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index); +#endif // FEATURE_PORTABLE_SPAN memoryHandle = new MemoryHandle(null, pointer, handle); } } @@ -267,7 +285,7 @@ namespace System } /// - /// Get an array segment from the underlying memory. + /// Get an array segment from the underlying memory. /// If unable to get the array segment, return false with a default array segment. /// public bool TryGetArray(out ArraySegment arraySegment) @@ -297,6 +315,10 @@ namespace System /// public T[] ToArray() => Span.ToArray(); + /// + /// Determines whether the specified object is equal to the current object. + /// Returns true if the object is Memory or ReadOnlyMemory and if both objects point to the same array and have the same length. + /// [EditorBrowsable(EditorBrowsableState.Never)] public override bool Equals(object obj) { @@ -326,6 +348,9 @@ namespace System _length == other._length; } + /// + /// Serves as the default hash function. + /// [EditorBrowsable(EditorBrowsableState.Never)] public override int GetHashCode() { diff --git a/src/mscorlib/shared/System/MemoryDebugView.cs b/src/mscorlib/shared/System/MemoryDebugView.cs index 2706d09..fa508b2 100644 --- a/src/mscorlib/shared/System/MemoryDebugView.cs +++ b/src/mscorlib/shared/System/MemoryDebugView.cs @@ -41,7 +41,11 @@ namespace System return (T[])(object)text.Substring(start, length).ToCharArray(); } +#if FEATURE_PORTABLE_SPAN + return SpanHelpers.PerTypeValues.EmptyArray; +#else return Array.Empty(); +#endif // FEATURE_PORTABLE_SPAN } } } diff --git a/src/mscorlib/shared/System/ReadOnlyMemory.cs b/src/mscorlib/shared/System/ReadOnlyMemory.cs index 5d8f00f..d0f8a47 100644 --- a/src/mscorlib/shared/System/ReadOnlyMemory.cs +++ b/src/mscorlib/shared/System/ReadOnlyMemory.cs @@ -8,7 +8,9 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; +#if !FEATURE_PORTABLE_SPAN using Internal.Runtime.CompilerServices; +#endif // FEATURE_PORTABLE_SPAN namespace System { @@ -96,7 +98,7 @@ namespace System /// Defines an implicit conversion of an array to a /// public static implicit operator ReadOnlyMemory(T[] array) => new ReadOnlyMemory(array); - + /// /// Defines an implicit conversion of a to a /// @@ -168,7 +170,11 @@ namespace System } else if (typeof(T) == typeof(char) && _object is string s) { +#if FEATURE_PORTABLE_SPAN + return new ReadOnlySpan(Unsafe.As>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length); +#else return new ReadOnlySpan(ref Unsafe.As(ref s.GetRawStringData()), s.Length).Slice(_index, _length); +#endif // FEATURE_PORTABLE_SPAN } else if (_object != null) { @@ -222,13 +228,21 @@ namespace System else if (typeof(T) == typeof(char) && _object is string s) { GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned); +#if FEATURE_PORTABLE_SPAN + void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); +#else void* pointer = Unsafe.Add(Unsafe.AsPointer(ref s.GetRawStringData()), _index); +#endif // FEATURE_PORTABLE_SPAN memoryHandle = new MemoryHandle(null, pointer, handle); } else if (_object is T[] array) { var handle = GCHandle.Alloc(array, GCHandleType.Pinned); +#if FEATURE_PORTABLE_SPAN + void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); +#else void* pointer = Unsafe.Add(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index); +#endif // FEATURE_PORTABLE_SPAN memoryHandle = new MemoryHandle(null, pointer, handle); } } @@ -286,7 +300,7 @@ namespace System { return _object != null ? CombineHashCodes(_object.GetHashCode(), _index.GetHashCode(), _length.GetHashCode()) : 0; } - + private static int CombineHashCodes(int left, int right) { return ((left << 5) + left) ^ right; diff --git a/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.cs b/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.cs index 2651df5..63e301b 100644 --- a/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.cs @@ -4,7 +4,9 @@ using System.Buffers; using System.Runtime.CompilerServices; +#if !FEATURE_PORTABLE_SPAN using Internal.Runtime.CompilerServices; +#endif // FEATURE_PORTABLE_SPAN namespace System.Runtime.InteropServices { @@ -26,10 +28,48 @@ namespace System.Runtime.InteropServices public static Memory AsMemory(ReadOnlyMemory readOnlyMemory) => Unsafe.As, Memory>(ref readOnlyMemory); +#if FEATURE_PORTABLE_SPAN + /// + /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element + /// would have been stored. Such a reference can be used for pinning but must never be dereferenced. + /// + public static ref T GetReference(Span span) + { + if (span.Pinnable == null) + unsafe { return ref Unsafe.AsRef(span.ByteOffset.ToPointer()); } + else + return ref Unsafe.AddByteOffset(ref span.Pinnable.Data, span.ByteOffset); + } + + /// + /// Returns a reference to the 0th element of the ReadOnlySpan. If the Span is empty, returns a reference to the location where the 0th element + /// would have been stored. Such a reference can be used for pinning but must never be dereferenced. + /// + public static ref T GetReference(ReadOnlySpan span) + { + if (span.Pinnable == null) + unsafe { return ref Unsafe.AsRef(span.ByteOffset.ToPointer()); } + else + return ref Unsafe.AddByteOffset(ref span.Pinnable.Data, span.ByteOffset); + } +#else + /// + /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element + /// would have been stored. Such a reference can be used for pinning but must never be dereferenced. + /// public static ref T GetReference(Span span) => ref span._pointer.Value; + /// + /// Returns a reference to the 0th element of the ReadOnlySpan. If the Span is empty, returns a reference to the location where the 0th element + /// would have been stored. Such a reference can be used for pinning but must never be dereferenced. + /// public static ref T GetReference(ReadOnlySpan span) => ref span._pointer.Value; +#endif // FEATURE_PORTABLE_SPAN + /// + /// Get an array segment from the underlying memory. + /// If unable to get the array segment, return false with a default array segment. + /// public static bool TryGetArray(ReadOnlyMemory readOnlyMemory, out ArraySegment arraySegment) { object obj = readOnlyMemory.GetObjectStartLength(out int index, out int length); diff --git a/src/mscorlib/src/System/ThrowHelper.cs b/src/mscorlib/src/System/ThrowHelper.cs index 09c7db4..cc9f43f 100644 --- a/src/mscorlib/src/System/ThrowHelper.cs +++ b/src/mscorlib/src/System/ThrowHelper.cs @@ -4,8 +4,8 @@ // This file defines an internal class used to throw exceptions in BCL code. -// The main purpose is to reduce code size. -// +// The main purpose is to reduce code size. +// // The old way to throw an exception generates quite a lot IL code and assembly code. // Following is an example: // C# source @@ -17,10 +17,10 @@ // IL_0012: newobj instance void System.ArgumentNullException::.ctor(string,string) // IL_0017: throw // which is 21bytes in IL. -// +// // So we want to get rid of the ldstr and call to Environment.GetResource in IL. // In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the -// argument name and resource name in a small integer. The source code will be changed to +// argument name and resource name in a small integer. The source code will be changed to // ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key); // // The IL code will be 7 bytes. @@ -29,11 +29,11 @@ // IL_000a: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument) // IL_000f: ldarg.0 // -// This will also reduce the Jitted code size a lot. +// This will also reduce the Jitted code size a lot. +// +// It is very important we do this for generic classes because we can easily generate the same code +// multiple times for different instantiation. // -// It is very important we do this for generic classes because we can easily generate the same code -// multiple times for different instantiation. -// using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -179,6 +179,11 @@ namespace System throw GetInvalidOperationException(resource); } + internal static void ThrowInvalidOperationException_OutstandingReferences() + { + ThrowInvalidOperationException(ExceptionResource.Memory_OutstandingReferences); + } + internal static void ThrowInvalidOperationException(ExceptionResource resource, Exception e) { throw new InvalidOperationException(GetResourceString(resource), e); @@ -219,6 +224,11 @@ namespace System throw new ObjectDisposedException(null, GetResourceString(resource)); } + internal static void ThrowObjectDisposedException_MemoryDisposed() + { + throw new ObjectDisposedException("OwnedMemory", GetResourceString(ExceptionResource.MemoryDisposed)); + } + internal static void ThrowNotSupportedException() { throw new NotSupportedException(); @@ -341,7 +351,7 @@ namespace System [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void IfNullAndNullsAreIllegalThenThrow(object value, ExceptionArgument argName) { - // Note that default(T) is not equal to null for value types except when T is Nullable. + // Note that default(T) is not equal to null for value types except when T is Nullable. if (!(default(T) == null) && value == null) ThrowHelper.ThrowArgumentNullException(argName); } @@ -368,9 +378,9 @@ namespace System internal static void ThrowNotSupportedExceptionIfNonNumericType() { - if (typeof(T) != typeof(Byte) && typeof(T) != typeof(SByte) && - typeof(T) != typeof(Int16) && typeof(T) != typeof(UInt16) && - typeof(T) != typeof(Int32) && typeof(T) != typeof(UInt32) && + if (typeof(T) != typeof(Byte) && typeof(T) != typeof(SByte) && + typeof(T) != typeof(Int16) && typeof(T) != typeof(UInt16) && + typeof(T) != typeof(Int32) && typeof(T) != typeof(UInt32) && typeof(T) != typeof(Int64) && typeof(T) != typeof(UInt64) && typeof(T) != typeof(Single) && typeof(T) != typeof(Double)) { @@ -381,7 +391,7 @@ namespace System // // The convention for this enum is using the argument name as the enum name - // + // internal enum ExceptionArgument { obj, @@ -465,7 +475,7 @@ namespace System // // The convention for this enum is using the resource name as the enum name - // + // internal enum ExceptionResource { Argument_ImplementIComparable, @@ -570,6 +580,7 @@ namespace System InvalidOperation_HandleIsNotInitialized, AsyncMethodBuilder_InstanceNotInitialized, ArgumentNull_SafeHandle, + MemoryDisposed, } }