Mirror changes from dotnet/corefx (#15909)
authordotnet bot <dotnet-bot@dotnetfoundation.org>
Thu, 18 Jan 2018 23:36:01 +0000 (15:36 -0800)
committerTarek Mahmoud Sayed <tarekms@microsoft.com>
Thu, 18 Jan 2018 23:36:01 +0000 (15:36 -0800)
* 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 <dotnet-bot@microsoft.com>
* Add missing throw helper methods used in the code we got from corefx

* Update the exception helper

* fix the break

src/mscorlib/Resources/Strings.resx
src/mscorlib/shared/System/Buffers/IRetainable.cs
src/mscorlib/shared/System/Buffers/MemoryHandle.cs
src/mscorlib/shared/System/Buffers/OwnedMemory.cs
src/mscorlib/shared/System/Memory.cs
src/mscorlib/shared/System/MemoryDebugView.cs
src/mscorlib/shared/System/ReadOnlyMemory.cs
src/mscorlib/shared/System/Runtime/InteropServices/MemoryMarshal.cs
src/mscorlib/src/System/ThrowHelper.cs

index 19d81b1..84679de 100644 (file)
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <root>
-  <!-- 
-    Microsoft ResX Schema 
-    
+  <!--
+    Microsoft ResX Schema
+
     Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
     associated with the data types.
-    
+
     Example:
-    
+
     ... ado.net/XML headers & schema ...
     <resheader name="resmimetype">text/microsoft-resx</resheader>
     <resheader name="version">2.0</resheader>
         <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
         <comment>This is a comment</comment>
     </data>
-                
-    There are any number of "resheader" rows that contain simple 
+
+    There are any number of "resheader" rows that contain simple
     name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
     mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
     extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
     read any of the formats listed below.
-    
+
     mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
+    value   : The object must be serialized with
             : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
             : and then encoded with base64 encoding.
-    
+
     mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
+    value   : The object must be serialized with
             : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
             : and then encoded with base64 encoding.
 
     mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
+    value   : The object must be serialized into a byte array
             : using a System.ComponentModel.TypeConverter
             : and then encoded with base64 encoding.
     -->
   <data name="Marshaler_StringTooLong" xml:space="preserve">
     <value>Marshaler restriction: Excessively long string.</value>
   </data>
+  <data name="MemoryDisposed" xml:space="preserve">
+    <value>Memory&lt;T&gt; has been disposed.</value>
+  </data>
   <data name="MissingConstructor_Name" xml:space="preserve">
     <value>Constructor on type '{0}' not found.</value>
   </data>
index 8d71fc6..6ac5088 100644 (file)
@@ -7,9 +7,20 @@ using System.Runtime.CompilerServices;
 
 namespace System.Buffers
 {
+    /// <summary>
+    /// Provides a mechanism for manual lifetime management.
+    /// </summary>
     public interface IRetainable
     {
+        /// <summary>
+        /// Call this method to indicate that the IRetainable object is in use.
+        /// Do not dispose until Release is called.
+        /// </summary>
         void Retain();
+        /// <summary>
+        /// Call this method to indicate that the IRetainable object is no longer in use.
+        /// The object can now be disposed.
+        /// </summary>
         bool Release();
     }
 }
\ No newline at end of file
index 6059214..01f9563 100644 (file)
@@ -7,20 +7,46 @@ using System.Runtime.InteropServices;
 
 namespace System.Buffers
 {
+    /// <summary>
+    /// A handle for the memory.
+    /// </summary>
     public unsafe struct MemoryHandle : IDisposable
     {
-        private IRetainable _owner;
+        private IRetainable _retainable;
         private void* _pointer;
         private GCHandle _handle;
 
+        /// <summary>
+        /// Creates a new memory handle for the memory.
+        /// </summary>
+        /// <param name="retainable">reference to manually managed object</param>
+        /// <param name="pointer">pointer to memory, or null if a pointer was not provided when the handle was created</param>
+        /// <param name="handle">handle used to pin array buffers</param>
         [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;
         }
 
+        /// <summary>
+        /// Returns the pointer to memory, or null if a pointer was not provided when the handle was created.
+        /// </summary>
+        [CLSCompliant(false)]
+        public void* Pointer => _pointer;
+
+        /// <summary>
+        /// Returns false if the pointer to memory is null.
+        /// </summary>
+        public bool HasPointer => _pointer != null;
+
+        /// <summary>
+        /// Adds an offset to the pinned pointer.
+        /// </summary>
+        /// <exception cref="System.ArgumentNullException">
+        /// Throw when pinned pointer is null.
+        /// </exception>
         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) 
+        /// <summary>
+        /// Frees the pinned handle and releases IRetainable.
+        /// </summary>
+       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
index 1167670..bbde61b 100644 (file)
@@ -7,46 +7,88 @@ using System.Runtime.CompilerServices;
 
 namespace System.Buffers
 {
+    /// <summary>
+    /// Owner of Memory<typeparamref name="T"/> that provides appropriate lifetime management mechanisms for it.
+    /// </summary>
     public abstract class OwnedMemory<T> : IDisposable, IRetainable
     {
+        /// <summary>
+        /// The number of items in the Memory<typeparamref name="T"/>.
+        /// </summary>
         public abstract int Length { get; }
 
+        /// <summary>
+        /// Returns a span wrapping the underlying memory.
+        /// </summary>
         public abstract Span<T> Span { get; }
 
+        /// <summary>
+        /// Returns a Memory<typeparamref name="T"/> if the underlying memory has not been freed.
+        /// </summary>
+        /// <exception cref="System.ObjectDisposedException">
+        /// Thrown when the underlying memory has already been disposed.
+        /// </exception>
         public Memory<T> Memory
         {
-            get 
+            get
             {
-                if (IsDisposed) 
+                if (IsDisposed)
                 {
-                    ThrowHelper.ThrowObjectDisposedException(nameof(OwnedMemory<T>), ExceptionResource.Memory_ThrowIfDisposed);
+                    ThrowHelper.ThrowObjectDisposedException_MemoryDisposed();
                 }
                 return new Memory<T>(owner: this, 0, Length);
             }
         }
 
+        /// <summary>
+        /// Returns a handle for the array that has been pinned and hence its address can be taken
+        /// </summary>
         public abstract MemoryHandle Pin();
 
+        /// <summary>
+        /// Returns an array segment.
+        /// </summary>
         protected internal abstract bool TryGetArray(out ArraySegment<T> arraySegment);
 
+        /// <summary>
+        /// Implements IDisposable.
+        /// </summary>
+        /// <exception cref="System.InvalidOperationException">
+        /// Throw when there are still retained references to the memory
+        /// </exception>
         public void Dispose()
         {
-            if (IsRetained) 
+            if (IsRetained)
             {
-                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Memory_OutstandingReferences);
+                ThrowHelper.ThrowInvalidOperationException_OutstandingReferences();
             }
             Dispose(true);
             GC.SuppressFinalize(this);
         }
 
+        /// <summary>
+        /// Clean up of any leftover managed and unmanaged resources.
+        /// </summary>
         protected abstract void Dispose(bool disposing);
 
+        /// <summary>
+        /// Return true if someone is holding a reference to the memory.
+        /// </summary>
         protected abstract bool IsRetained { get; }
 
+        /// <summary>
+        /// Return true if the underlying memory has been freed.
+        /// </summary>
         public abstract bool IsDisposed { get; }
 
+        /// <summary>
+        /// Implements IRetainable. Prevent accidental disposal of the memory.
+        /// </summary>
         public abstract void Retain();
 
+        /// <summary>
+        /// Implements IRetainable. The memory can now be diposed.
+        /// </summary>
         public abstract bool Release();
 
     }
index 2286d69..9cb6e38 100644 (file)
@@ -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
 {
+    /// <summary>
+    /// Memory represents a contiguous region of arbitrary memory similar to <see cref="Span{T}"/>.
+    /// Unlike <see cref="Span{T}"/>, it is not a byref-like type.
+    /// </summary>
     [DebuggerDisplay("{DebuggerDisplay,nq}")]
     [DebuggerTypeProxy(typeof(MemoryDebugView<>))]
     public readonly struct Memory<T>
@@ -77,16 +83,12 @@ namespace System
             _index = start;
             _length = length;
         }
-        
+
         // Constructor for internal use only.
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal Memory(OwnedMemory<T> 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 <see cref="Memory{T}"/>
         /// </summary>
         public static implicit operator Memory<T>(T[] array) => new Memory<T>(array);
-        
+
         /// <summary>
         /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Memory{T}"/>
         /// </summary>
@@ -168,7 +170,7 @@ namespace System
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException();
             }
-            
+
             return new Memory<T>(_object, _index + start, length);
         }
 
@@ -191,7 +193,11 @@ namespace System
                     // and then cast to a Memory<T>. 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<T>(Unsafe.As<Pinnable<T>>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length);
+#else
                     return new Span<T>(ref Unsafe.As<char, T>(ref s.GetRawStringData()), s.Length).Slice(_index, _length);
+#endif // FEATURE_PORTABLE_SPAN
                 }
                 else if (_object != null)
                 {
@@ -227,6 +233,10 @@ namespace System
         /// <param name="destination">The span to copy items into.</param>
         public bool TryCopyTo(Memory<T> destination) => Span.TryCopyTo(destination.Span);
 
+        /// <summary>
+        /// Returns a handle for the array.
+        /// <param name="pin">If pin is true, the GC will not move the array and hence its address can be taken</param>
+        /// </summary>
         public unsafe MemoryHandle Retain(bool pin = false)
         {
             MemoryHandle memoryHandle = default;
@@ -245,13 +255,21 @@ namespace System
                     // a readable ReadOnlyMemory<char> or a writable Memory<char> can still be pinned and
                     // used for interop purposes.
                     GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+                    void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
                     void* pointer = Unsafe.Add<T>(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<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
                     void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
                     memoryHandle = new MemoryHandle(null, pointer, handle);
                 }
             }
@@ -267,7 +285,7 @@ namespace System
         }
 
         /// <summary>
-        /// 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.
         /// </summary>
         public bool TryGetArray(out ArraySegment<T> arraySegment)
@@ -297,6 +315,10 @@ namespace System
         /// </summary>
         public T[] ToArray() => Span.ToArray();
 
+        /// <summary>
+        /// 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.
+        /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public override bool Equals(object obj)
         {
@@ -326,6 +348,9 @@ namespace System
                 _length == other._length;
         }
 
+        /// <summary>
+        /// Serves as the default hash function.
+        /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public override int GetHashCode()
         {
index 2706d09..fa508b2 100644 (file)
@@ -41,7 +41,11 @@ namespace System
                     return (T[])(object)text.Substring(start, length).ToCharArray();
                 }
 
+#if FEATURE_PORTABLE_SPAN
+                return SpanHelpers.PerTypeValues<T>.EmptyArray;
+#else
                 return Array.Empty<T>();
+#endif // FEATURE_PORTABLE_SPAN
             }
         }
     }
index 5d8f00f..d0f8a47 100644 (file)
@@ -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 <see cref="ReadOnlyMemory{T}"/>
         /// </summary>
         public static implicit operator ReadOnlyMemory<T>(T[] array) => new ReadOnlyMemory<T>(array);
-        
+
         /// <summary>
         /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="ReadOnlyMemory{T}"/>
         /// </summary>
@@ -168,7 +170,11 @@ namespace System
                 }
                 else if (typeof(T) == typeof(char) && _object is string s)
                 {
+#if FEATURE_PORTABLE_SPAN
+                    return new ReadOnlySpan<T>(Unsafe.As<Pinnable<T>>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length);
+#else
                     return new ReadOnlySpan<T>(ref Unsafe.As<char, T>(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<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
                     void* pointer = Unsafe.Add<T>(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<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
                     void* pointer = Unsafe.Add<T>(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;
index 2651df5..63e301b 100644 (file)
@@ -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<T> AsMemory<T>(ReadOnlyMemory<T> readOnlyMemory) =>
             Unsafe.As<ReadOnlyMemory<T>, Memory<T>>(ref readOnlyMemory);
 
+#if FEATURE_PORTABLE_SPAN
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public static ref T GetReference<T>(Span<T> span)
+        {
+            if (span.Pinnable == null)
+                unsafe { return ref Unsafe.AsRef<T>(span.ByteOffset.ToPointer()); }
+            else
+                return ref Unsafe.AddByteOffset<T>(ref span.Pinnable.Data, span.ByteOffset);
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public static ref T GetReference<T>(ReadOnlySpan<T> span)
+        {
+            if (span.Pinnable == null)
+                unsafe { return ref Unsafe.AsRef<T>(span.ByteOffset.ToPointer()); }
+            else
+                return ref Unsafe.AddByteOffset<T>(ref span.Pinnable.Data, span.ByteOffset);
+        }
+#else
+        /// <summary>
+        /// 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.
+        /// </summary>
         public static ref T GetReference<T>(Span<T> span) => ref span._pointer.Value;
 
+        /// <summary>
+        /// 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.
+        /// </summary>
         public static ref T GetReference<T>(ReadOnlySpan<T> span) => ref span._pointer.Value;
+#endif // FEATURE_PORTABLE_SPAN
 
+        /// <summary>
+        /// Get an array segment from the underlying memory.
+        /// If unable to get the array segment, return false with a default array segment.
+        /// </summary>
         public static bool TryGetArray<T>(ReadOnlyMemory<T> readOnlyMemory, out ArraySegment<T> arraySegment)
         {
             object obj = readOnlyMemory.GetObjectStartLength(out int index, out int length);
index 09c7db4..cc9f43f 100644 (file)
@@ -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
 //          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.
 //    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<T>", GetResourceString(ExceptionResource.MemoryDisposed));
+        }
+
         internal static void ThrowNotSupportedException()
         {
             throw new NotSupportedException();
@@ -341,7 +351,7 @@ namespace System
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal static void IfNullAndNullsAreIllegalThenThrow<T>(object value, ExceptionArgument argName)
         {
-            // Note that default(T) is not equal to null for value types except when T is Nullable<U>. 
+            // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
             if (!(default(T) == null) && value == null)
                 ThrowHelper.ThrowArgumentNullException(argName);
         }
@@ -368,9 +378,9 @@ namespace System
 
         internal static void ThrowNotSupportedExceptionIfNonNumericType<T>()
         {
-            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,
     }
 }