From: Jan Kotas Date: Tue, 21 Nov 2017 14:01:12 +0000 (-0800) Subject: Move UnmanagedMemoryAccessor to shared CoreLib partition (#15137) X-Git-Tag: accepted/tizen/base/20180629.140029~505 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7fe84b111b94c7773aee3b6dca468d657a61fdca;p=platform%2Fupstream%2Fcoreclr.git Move UnmanagedMemoryAccessor to shared CoreLib partition (#15137) --- diff --git a/src/mscorlib/Resources/Strings.resx b/src/mscorlib/Resources/Strings.resx index a905183..b975448 100644 --- a/src/mscorlib/Resources/Strings.resx +++ b/src/mscorlib/Resources/Strings.resx @@ -1408,9 +1408,6 @@ Offset and capacity were greater than the size of the view. - - Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. - The UTC Offset of the local dateTime parameter does not match the offset argument. diff --git a/src/mscorlib/System.Private.CoreLib.csproj b/src/mscorlib/System.Private.CoreLib.csproj index 4bae50a..e39b73e 100644 --- a/src/mscorlib/System.Private.CoreLib.csproj +++ b/src/mscorlib/System.Private.CoreLib.csproj @@ -519,7 +519,6 @@ - diff --git a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems index 7138185..ab7dc93 100644 --- a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems @@ -206,6 +206,7 @@ + diff --git a/src/mscorlib/shared/System/BitConverter.cs b/src/mscorlib/shared/System/BitConverter.cs index edcdd1e..6814047 100644 --- a/src/mscorlib/shared/System/BitConverter.cs +++ b/src/mscorlib/shared/System/BitConverter.cs @@ -36,7 +36,7 @@ namespace System if (destination.Length < sizeof(byte)) return false; - Unsafe.WriteUnaligned(ref destination.DangerousGetPinnableReference(), value ? (byte)1: (byte)0); + Unsafe.WriteUnaligned(ref destination.DangerousGetPinnableReference(), value ? (byte)1 : (byte)0); return true; } @@ -217,7 +217,7 @@ namespace System } // Converts an array of bytes into a char. - public static char ToChar(byte[] value, int startIndex) => unchecked((char)ReadInt16(value, startIndex)); + public static char ToChar(byte[] value, int startIndex) => unchecked((char)ToInt16(value, startIndex)); // Converts a Span into a char public static char ToChar(ReadOnlySpan value) @@ -227,7 +227,8 @@ namespace System return Unsafe.ReadUnaligned(ref value.DangerousGetPinnableReference()); } - private static short ReadInt16(byte[] value, int startIndex) + // Converts an array of bytes into a short. + public static short ToInt16(byte[] value, int startIndex) { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); @@ -239,44 +240,27 @@ namespace System return Unsafe.ReadUnaligned(ref value[startIndex]); } - private static int ReadInt32(byte[] value, int startIndex) + // Converts a Span into a short + public static short ToInt16(ReadOnlySpan value) { - if (value == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - if (unchecked((uint)startIndex) >= unchecked((uint)value.Length)) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); - if (startIndex > value.Length - sizeof(int)) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); - - return Unsafe.ReadUnaligned(ref value[startIndex]); + if (value.Length < sizeof(short)) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); + return Unsafe.ReadUnaligned(ref value.DangerousGetPinnableReference()); } - private static long ReadInt64(byte[] value, int startIndex) + // Converts an array of bytes into an int. + public static int ToInt32(byte[] value, int startIndex) { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); if (unchecked((uint)startIndex) >= unchecked((uint)value.Length)) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); - if (startIndex > value.Length - sizeof(long)) + if (startIndex > value.Length - sizeof(int)) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); - return Unsafe.ReadUnaligned(ref value[startIndex]); - } - - // Converts an array of bytes into a short. - public static short ToInt16(byte[] value, int startIndex) => ReadInt16(value, startIndex); - - // Converts a Span into a short - public static short ToInt16(ReadOnlySpan value) - { - if (value.Length < sizeof(short)) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value); - return Unsafe.ReadUnaligned(ref value.DangerousGetPinnableReference()); + return Unsafe.ReadUnaligned(ref value[startIndex]); } - // Converts an array of bytes into an int. - public static int ToInt32(byte[] value, int startIndex) => ReadInt32(value, startIndex); - // Converts a Span into an int public static int ToInt32(ReadOnlySpan value) { @@ -286,7 +270,17 @@ namespace System } // Converts an array of bytes into a long. - public static long ToInt64(byte[] value, int startIndex) => ReadInt64(value, startIndex); + public static long ToInt64(byte[] value, int startIndex) + { + if (value == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); + if (unchecked((uint)startIndex) >= unchecked((uint)value.Length)) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); + if (startIndex > value.Length - sizeof(long)) + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); + + return Unsafe.ReadUnaligned(ref value[startIndex]); + } // Converts a Span into a long public static long ToInt64(ReadOnlySpan value) @@ -299,7 +293,7 @@ namespace System // Converts an array of bytes into an ushort. // [CLSCompliant(false)] - public static ushort ToUInt16(byte[] value, int startIndex) => unchecked((ushort)ReadInt16(value, startIndex)); + public static ushort ToUInt16(byte[] value, int startIndex) => unchecked((ushort)ToInt16(value, startIndex)); // Converts a Span into a ushort [CLSCompliant(false)] @@ -313,7 +307,7 @@ namespace System // Converts an array of bytes into an uint. // [CLSCompliant(false)] - public static uint ToUInt32(byte[] value, int startIndex) => unchecked((uint)ReadInt32(value, startIndex)); + public static uint ToUInt32(byte[] value, int startIndex) => unchecked((uint)ToInt32(value, startIndex)); // Convert a Span into a uint [CLSCompliant(false)] @@ -327,7 +321,7 @@ namespace System // Converts an array of bytes into an unsigned long. // [CLSCompliant(false)] - public static ulong ToUInt64(byte[] value, int startIndex) => unchecked((ulong)ReadInt64(value, startIndex)); + public static ulong ToUInt64(byte[] value, int startIndex) => unchecked((ulong)ToInt64(value, startIndex)); // Converts a Span into an unsigned long [CLSCompliant(false)] @@ -339,11 +333,7 @@ namespace System } // Converts an array of bytes into a float. - public static unsafe float ToSingle(byte[] value, int startIndex) - { - int val = ReadInt32(value, startIndex); - return *(float*)&val; - } + public static float ToSingle(byte[] value, int startIndex) => Int32BitsToSingle(ToInt32(value, startIndex)); // Converts a Span into a float public static float ToSingle(ReadOnlySpan value) @@ -354,11 +344,7 @@ namespace System } // Converts an array of bytes into a double. - public static unsafe double ToDouble(byte[] value, int startIndex) - { - long val = ReadInt64(value, startIndex); - return *(double*)&val; - } + public static double ToDouble(byte[] value, int startIndex) => Int64BitsToDouble(ToInt64(value, startIndex)); // Converts a Span into a double public static double ToDouble(ReadOnlySpan value) diff --git a/src/mscorlib/shared/System/IO/UnmanagedMemoryAccessor.cs b/src/mscorlib/shared/System/IO/UnmanagedMemoryAccessor.cs new file mode 100644 index 0000000..4899d57 --- /dev/null +++ b/src/mscorlib/shared/System/IO/UnmanagedMemoryAccessor.cs @@ -0,0 +1,669 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================ +** +** +** +** +** Purpose: Provides a fast, AV free, cross-language way of +** accessing unmanaged memory in a random fashion. +** +** +===========================================================*/ + +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.IO +{ + /// Perf notes: ReadXXX, WriteXXX (for basic types) acquire and release the + /// SafeBuffer pointer rather than relying on generic Read(T) from SafeBuffer because + /// this gives better throughput; benchmarks showed about 12-15% better. + public class UnmanagedMemoryAccessor : IDisposable + { + private SafeBuffer _buffer; + private long _offset; + private long _capacity; + private FileAccess _access; + private bool _isOpen; + private bool _canRead; + private bool _canWrite; + + protected UnmanagedMemoryAccessor() + { + _isOpen = false; + } + + public UnmanagedMemoryAccessor(SafeBuffer buffer, long offset, long capacity) + { + Initialize(buffer, offset, capacity, FileAccess.Read); + } + + public UnmanagedMemoryAccessor(SafeBuffer buffer, long offset, long capacity, FileAccess access) + { + Initialize(buffer, offset, capacity, access); + } + + protected void Initialize(SafeBuffer buffer, long offset, long capacity, FileAccess access) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (capacity < 0) + { + throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.ByteLength < (ulong)(offset + capacity)) + { + throw new ArgumentException(SR.Argument_OffsetAndCapacityOutOfBounds); + } + if (access < FileAccess.Read || access > FileAccess.ReadWrite) + { + throw new ArgumentOutOfRangeException(nameof(access)); + } + + if (_isOpen) + { + throw new InvalidOperationException(SR.InvalidOperation_CalledTwice); + } + + unsafe + { + byte* pointer = null; + + try + { + buffer.AcquirePointer(ref pointer); + if (((byte*)((long)pointer + offset + capacity)) < pointer) + { + throw new ArgumentException(SR.Argument_UnmanagedMemAccessorWrapAround); + } + } + finally + { + if (pointer != null) + { + buffer.ReleasePointer(); + } + } + } + + _offset = offset; + _buffer = buffer; + _capacity = capacity; + _access = access; + _isOpen = true; + _canRead = (_access & FileAccess.Read) != 0; + _canWrite = (_access & FileAccess.Write) != 0; + } + + public long Capacity => _capacity; + + public bool CanRead => _isOpen && _canRead; + + public bool CanWrite => _isOpen && _canWrite; + + protected virtual void Dispose(bool disposing) + { + _isOpen = false; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected bool IsOpen => _isOpen; + + // ************** Read Methods ****************/ + + public bool ReadBoolean(long position) => ReadByte(position) != 0; + + public byte ReadByte(long position) + { + EnsureSafeToRead(position, sizeof(byte)); + + byte result; + unsafe + { + byte* pointer = null; + + try + { + _buffer.AcquirePointer(ref pointer); + result = *((byte*)(pointer + _offset + position)); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } + return result; + } + + public char ReadChar(long position) => unchecked((char)ReadInt16(position)); + + public short ReadInt16(long position) + { + EnsureSafeToRead(position, sizeof(short)); + + short result; + unsafe + { + byte* pointer = null; + + try + { + _buffer.AcquirePointer(ref pointer); + result = Unsafe.ReadUnaligned(pointer + _offset + position); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } + return result; + } + + public int ReadInt32(long position) + { + EnsureSafeToRead(position, sizeof(int)); + + int result; + unsafe + { + byte* pointer = null; + + try + { + _buffer.AcquirePointer(ref pointer); + result = Unsafe.ReadUnaligned(pointer + _offset + position); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } + return result; + } + + public long ReadInt64(long position) + { + EnsureSafeToRead(position, sizeof(long)); + + long result; + unsafe + { + byte* pointer = null; + + try + { + _buffer.AcquirePointer(ref pointer); + result = Unsafe.ReadUnaligned(pointer + _offset + position); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } + return result; + } + + public decimal ReadDecimal(long position) + { + const int ScaleMask = 0x00FF0000; + const int SignMask = unchecked((int)0x80000000); + + EnsureSafeToRead(position, sizeof(decimal)); + + int lo, mid, hi, flags; + + unsafe + { + byte* pointer = null; + try + { + _buffer.AcquirePointer(ref pointer); + pointer += (_offset + position); + + lo = Unsafe.ReadUnaligned(pointer); + mid = Unsafe.ReadUnaligned(pointer + 4); + hi = Unsafe.ReadUnaligned(pointer + 8); + flags = Unsafe.ReadUnaligned(pointer + 12); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } + + // Check for invalid Decimal values + if (!((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16))) + { + throw new ArgumentException(SR.Arg_BadDecimal); // Throw same Exception type as Decimal(int[]) ctor for compat + } + + bool isNegative = (flags & SignMask) != 0; + byte scale = (byte)(flags >> 16); + + return new decimal(lo, mid, hi, isNegative, scale); + } + + public float ReadSingle(long position) => BitConverter.Int32BitsToSingle(ReadInt32(position)); + + public double ReadDouble(long position) => BitConverter.Int64BitsToDouble(ReadInt64(position)); + + [CLSCompliant(false)] + public sbyte ReadSByte(long position) => unchecked((sbyte)ReadByte(position)); + + [CLSCompliant(false)] + public ushort ReadUInt16(long position) => unchecked((ushort)ReadInt16(position)); + + [CLSCompliant(false)] + public uint ReadUInt32(long position) => unchecked((uint)ReadInt32(position)); + + [CLSCompliant(false)] + public ulong ReadUInt64(long position) => unchecked((ulong)ReadInt64(position)); + + // Reads a struct of type T from unmanaged memory, into the reference pointed to by ref value. + // Note: this method is not safe, since it overwrites the contents of a structure, it can be + // used to modify the private members of a struct. + // This method is most performant when used with medium to large sized structs + // (larger than 8 bytes -- though this is number is JIT and architecture dependent). As + // such, it is best to use the ReadXXX methods for small standard types such as ints, longs, + // bools, etc. + public void Read(long position, out T structure) where T : struct + { + if (position < 0) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); + } + + if (!_isOpen) + { + throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed); + } + if (!_canRead) + { + throw new NotSupportedException(SR.NotSupported_Reading); + } + + uint sizeOfT = SafeBuffer.SizeOf(); + if (position > _capacity - sizeOfT) + { + if (position >= _capacity) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); + } + else + { + throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToRead, typeof(T)), nameof(position)); + } + } + + structure = _buffer.Read((ulong)(_offset + position)); + } + + // Reads 'count' structs of type T from unmanaged memory, into 'array' starting at 'offset'. + // Note: this method is not safe, since it overwrites the contents of structures, it can + // be used to modify the private members of a struct. + public int ReadArray(long position, T[] array, int offset, int count) where T : struct + { + if (array == null) + { + throw new ArgumentNullException(nameof(array), SR.ArgumentNull_Buffer); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (array.Length - offset < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + if (!_isOpen) + { + throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed); + } + if (!_canRead) + { + throw new NotSupportedException(SR.NotSupported_Reading); + } + if (position < 0) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); + } + + uint sizeOfT = SafeBuffer.AlignedSizeOf(); + + // only check position and ask for fewer Ts if count is too big + if (position >= _capacity) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); + } + + int n = count; + long spaceLeft = _capacity - position; + if (spaceLeft < 0) + { + n = 0; + } + else + { + ulong spaceNeeded = (ulong)(sizeOfT * count); + if ((ulong)spaceLeft < spaceNeeded) + { + n = (int)(spaceLeft / sizeOfT); + } + } + + _buffer.ReadArray((ulong)(_offset + position), array, offset, n); + + return n; + } + + // ************** Write Methods ****************/ + + public void Write(long position, bool value) => Write(position, (byte)(value ? 1 : 0)); + + public void Write(long position, byte value) + { + EnsureSafeToWrite(position, sizeof(byte)); + + unsafe + { + byte* pointer = null; + + try + { + _buffer.AcquirePointer(ref pointer); + *((byte*)(pointer + _offset + position)) = value; + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } + } + + public void Write(long position, char value) => Write(position, unchecked((short)value)); + + public void Write(long position, short value) + { + EnsureSafeToWrite(position, sizeof(short)); + + unsafe + { + byte* pointer = null; + + try + { + _buffer.AcquirePointer(ref pointer); + Unsafe.WriteUnaligned(pointer + _offset + position, value); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } + } + + public void Write(long position, int value) + { + EnsureSafeToWrite(position, sizeof(int)); + + unsafe + { + byte* pointer = null; + + try + { + _buffer.AcquirePointer(ref pointer); + Unsafe.WriteUnaligned(pointer + _offset + position, value); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } + } + + public void Write(long position, long value) + { + EnsureSafeToWrite(position, sizeof(long)); + + unsafe + { + byte* pointer = null; + + try + { + _buffer.AcquirePointer(ref pointer); + Unsafe.WriteUnaligned(pointer + _offset + position, value); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } + } + + public void Write(long position, decimal value) + { + EnsureSafeToWrite(position, sizeof(decimal)); + + unsafe + { + int* valuePtr = (int*)(&value); + int flags = *valuePtr; + int hi = *(valuePtr + 1); + int lo = *(valuePtr + 2); + int mid = *(valuePtr + 3); + + byte* pointer = null; + try + { + _buffer.AcquirePointer(ref pointer); + pointer += (_offset + position); + + Unsafe.WriteUnaligned(pointer, lo); + Unsafe.WriteUnaligned(pointer + 4, mid); + Unsafe.WriteUnaligned(pointer + 8, hi); + Unsafe.WriteUnaligned(pointer + 12, flags); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } + } + + public void Write(long position, float value) => Write(position, BitConverter.SingleToInt32Bits(value)); + + public void Write(long position, double value) => Write(position, BitConverter.DoubleToInt64Bits(value)); + + [CLSCompliant(false)] + public void Write(long position, sbyte value) => Write(position, unchecked((byte)value)); + + [CLSCompliant(false)] + public void Write(long position, ushort value) => Write(position, unchecked((short)value)); + + [CLSCompliant(false)] + public void Write(long position, uint value) => Write(position, unchecked((int)value)); + + [CLSCompliant(false)] + public void Write(long position, ulong value) => Write(position, unchecked((long)value)); + + // Writes the struct pointed to by ref value into unmanaged memory. Note that this method + // is most performant when used with medium to large sized structs (larger than 8 bytes + // though this is number is JIT and architecture dependent). As such, it is best to use + // the WriteX methods for small standard types such as ints, longs, bools, etc. + public void Write(long position, ref T structure) where T : struct + { + if (position < 0) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (!_isOpen) + { + throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed); + } + if (!_canWrite) + { + throw new NotSupportedException(SR.NotSupported_Writing); + } + + uint sizeOfT = SafeBuffer.SizeOf(); + if (position > _capacity - sizeOfT) + { + if (position >= _capacity) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); + } + else + { + throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToWrite, typeof(T)), nameof(position)); + } + } + + _buffer.Write((ulong)(_offset + position), structure); + } + + // Writes 'count' structs of type T from 'array' (starting at 'offset') into unmanaged memory. + public void WriteArray(long position, T[] array, int offset, int count) where T : struct + { + if (array == null) + { + throw new ArgumentNullException(nameof(array), SR.ArgumentNull_Buffer); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (array.Length - offset < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + if (position < 0) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (position >= Capacity) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); + } + + if (!_isOpen) + { + throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed); + } + if (!_canWrite) + { + throw new NotSupportedException(SR.NotSupported_Writing); + } + + _buffer.WriteArray((ulong)(_offset + position), array, offset, count); + } + + private void EnsureSafeToRead(long position, int sizeOfType) + { + if (!_isOpen) + { + throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed); + } + if (!_canRead) + { + throw new NotSupportedException(SR.NotSupported_Reading); + } + if (position < 0) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (position > _capacity - sizeOfType) + { + if (position >= _capacity) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); + } + else + { + throw new ArgumentException(SR.Argument_NotEnoughBytesToRead, nameof(position)); + } + } + } + + private void EnsureSafeToWrite(long position, int sizeOfType) + { + if (!_isOpen) + { + throw new ObjectDisposedException(nameof(UnmanagedMemoryAccessor), SR.ObjectDisposed_ViewAccessorClosed); + } + if (!_canWrite) + { + throw new NotSupportedException(SR.NotSupported_Writing); + } + if (position < 0) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (position > _capacity - sizeOfType) + { + if (position >= _capacity) + { + throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); + } + else + { + throw new ArgumentException(SR.Argument_NotEnoughBytesToWrite, nameof(position)); + } + } + } + } +} diff --git a/src/mscorlib/src/System/IO/UnmanagedMemoryAccessor.cs b/src/mscorlib/src/System/IO/UnmanagedMemoryAccessor.cs deleted file mode 100644 index 43f2869..0000000 --- a/src/mscorlib/src/System/IO/UnmanagedMemoryAccessor.cs +++ /dev/null @@ -1,1077 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** -** -** -** Purpose: Provides a fast, AV free, cross-language way of -** accessing unmanaged memory in a random fashion. -** -** -===========================================================*/ - -using System; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Runtime.ConstrainedExecution; -using System.Runtime.Versioning; -using Microsoft.Win32.SafeHandles; -using System.Diagnostics; - -namespace System.IO -{ - /// Perf notes: ReadXXX, WriteXXX (for basic types) acquire and release the - /// SafeBuffer pointer rather than relying on generic Read(T) from SafeBuffer because - /// this gives better throughput; benchmarks showed about 12-15% better. - public class UnmanagedMemoryAccessor : IDisposable - { - private SafeBuffer _buffer; - private Int64 _offset; - private Int64 _capacity; - private FileAccess _access; - private bool _isOpen; - private bool _canRead; - private bool _canWrite; - - protected UnmanagedMemoryAccessor() - { - _isOpen = false; - } - - #region SafeBuffer ctors and initializers - // - // - // - public UnmanagedMemoryAccessor(SafeBuffer buffer, Int64 offset, Int64 capacity) - { - Initialize(buffer, offset, capacity, FileAccess.Read); - } - - public UnmanagedMemoryAccessor(SafeBuffer buffer, Int64 offset, Int64 capacity, FileAccess access) - { - Initialize(buffer, offset, capacity, access); - } - - protected void Initialize(SafeBuffer buffer, Int64 offset, Int64 capacity, FileAccess access) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - if (offset < 0) - { - throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (capacity < 0) - { - throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (buffer.ByteLength < (UInt64)(offset + capacity)) - { - throw new ArgumentException(SR.Argument_OffsetAndCapacityOutOfBounds); - } - if (access < FileAccess.Read || access > FileAccess.ReadWrite) - { - throw new ArgumentOutOfRangeException(nameof(access)); - } - - if (_isOpen) - { - throw new InvalidOperationException(SR.InvalidOperation_CalledTwice); - } - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - buffer.AcquirePointer(ref pointer); - if (((byte*)((Int64)pointer + offset + capacity)) < pointer) - { - throw new ArgumentException(SR.Argument_UnmanagedMemAccessorWrapAround); - } - } - finally - { - if (pointer != null) - { - buffer.ReleasePointer(); - } - } - } - - _offset = offset; - _buffer = buffer; - _capacity = capacity; - _access = access; - _isOpen = true; - _canRead = (_access & FileAccess.Read) != 0; - _canWrite = (_access & FileAccess.Write) != 0; - } - - #endregion - - public Int64 Capacity - { - get - { - return _capacity; - } - } - - public bool CanRead - { - get - { - return _isOpen && _canRead; - } - } - - public bool CanWrite - { - get - { - return _isOpen && _canWrite; - } - } - - protected virtual void Dispose(bool disposing) - { - _isOpen = false; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected bool IsOpen - { - get { return _isOpen; } - } - - public bool ReadBoolean(Int64 position) - { - int sizeOfType = sizeof(bool); - EnsureSafeToRead(position, sizeOfType); - - byte b = InternalReadByte(position); - return b != 0; - } - - public byte ReadByte(Int64 position) - { - int sizeOfType = sizeof(byte); - EnsureSafeToRead(position, sizeOfType); - - return InternalReadByte(position); - } - - public char ReadChar(Int64 position) - { - EnsureSafeToRead(position, sizeof(char)); - - char result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = Unsafe.ReadUnaligned(pointer + _offset + position); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - return result; - } - - // See comment above. - public Int16 ReadInt16(Int64 position) - { - EnsureSafeToRead(position, sizeof(Int16)); - - Int16 result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = Unsafe.ReadUnaligned(pointer + _offset + position); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - return result; - } - - - public Int32 ReadInt32(Int64 position) - { - EnsureSafeToRead(position, sizeof(Int32)); - - Int32 result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = Unsafe.ReadUnaligned(pointer + _offset + position); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - return result; - } - - public Int64 ReadInt64(Int64 position) - { - EnsureSafeToRead(position, sizeof(Int64)); - - Int64 result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = Unsafe.ReadUnaligned(pointer + _offset + position); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - return result; - } - - public Decimal ReadDecimal(Int64 position) - { - const int ScaleMask = 0x00FF0000; - const int SignMask = unchecked((int)0x80000000); - - EnsureSafeToRead(position, sizeof(Decimal)); - - int lo, mid, hi, flags; - - unsafe - { - byte* pointer = null; - try - { - _buffer.AcquirePointer(ref pointer); - - lo = Unsafe.ReadUnaligned(pointer + _offset + position); - mid = Unsafe.ReadUnaligned(pointer + _offset + position + 4); - hi = Unsafe.ReadUnaligned(pointer + _offset + position + 8); - flags = Unsafe.ReadUnaligned(pointer + _offset + position + 12); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - // Check for invalid Decimal values - if (!((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16))) - { - throw new ArgumentException(SR.Arg_BadDecimal); // Throw same Exception type as Decimal(int[]) ctor for compat - } - - bool isNegative = (flags & SignMask) != 0; - byte scale = (byte)(flags >> 16); - - return new decimal(lo, mid, hi, isNegative, scale); - } - - public Single ReadSingle(Int64 position) - { - EnsureSafeToRead(position, sizeof(Single)); - - Single result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = Unsafe.ReadUnaligned(pointer + _offset + position); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - return result; - } - - public Double ReadDouble(Int64 position) - { - EnsureSafeToRead(position, sizeof(Double)); - - Double result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = Unsafe.ReadUnaligned(pointer + _offset + position); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - return result; - } - - [CLSCompliant(false)] - public SByte ReadSByte(Int64 position) - { - int sizeOfType = sizeof(SByte); - EnsureSafeToRead(position, sizeOfType); - - SByte result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = *((SByte*)(pointer + _offset + position)); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - return result; - } - - [CLSCompliant(false)] - public UInt16 ReadUInt16(Int64 position) - { - EnsureSafeToRead(position, sizeof(UInt16)); - - UInt16 result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = Unsafe.ReadUnaligned(pointer + _offset + position); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - return result; - } - - [CLSCompliant(false)] - public UInt32 ReadUInt32(Int64 position) - { - EnsureSafeToRead(position, sizeof(UInt32)); - - UInt32 result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = Unsafe.ReadUnaligned(pointer + _offset + position); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - return result; - } - - [CLSCompliant(false)] - public UInt64 ReadUInt64(Int64 position) - { - EnsureSafeToRead(position, sizeof(UInt64)); - - UInt64 result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = Unsafe.ReadUnaligned(pointer + _offset + position); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - - return result; - } - - // Reads a struct of type T from unmanaged memory, into the reference pointed to by ref value. - // Note: this method is not safe, since it overwrites the contents of a structure, it can be - // used to modify the private members of a struct. Furthermore, using this with a struct that - // contains reference members will most likely cause the runtime to AV. Note, that despite - // various checks made by the C++ code used by Marshal.PtrToStructure, Marshal.PtrToStructure - // will still overwrite privates and will also crash the runtime when used with structs - // containing reference members. For this reason, I am sticking an UnmanagedCode requirement - // on this method to match Marshal.PtrToStructure. - - // Alos note that this method is most performant when used with medium to large sized structs - // (larger than 8 bytes -- though this is number is JIT and architecture dependent). As - // such, it is best to use the ReadXXX methods for small standard types such as ints, longs, - // bools, etc. - - public void Read(Int64 position, out T structure) where T : struct - { - if (position < 0) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); - } - - if (!_isOpen) - { - throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed); - } - if (!CanRead) - { - throw new NotSupportedException(SR.NotSupported_Reading); - } - - UInt32 sizeOfT = Marshal.SizeOfType(typeof(T)); - if (position > _capacity - sizeOfT) - { - if (position >= _capacity) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); - } - else - { - throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToRead, typeof (T).FullName), nameof(position)); - } - } - - structure = _buffer.Read((UInt64)(_offset + position)); - } - - // Reads 'count' structs of type T from unmanaged memory, into 'array' starting at 'offset'. - // Note: this method is not safe, since it overwrites the contents of structures, it can - // be used to modify the private members of a struct. Furthermore, using this with a - // struct that contains reference members will most likely cause the runtime to AV. This - // is consistent with Marshal.PtrToStructure. - - public int ReadArray(Int64 position, T[] array, Int32 offset, Int32 count) where T : struct - { - if (array == null) - { - throw new ArgumentNullException(nameof(array), "Buffer cannot be null."); - } - if (offset < 0) - { - throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (array.Length - offset < count) - { - throw new ArgumentException(SR.Argument_OffsetAndLengthOutOfBounds); - } - if (!CanRead) - { - if (!_isOpen) - { - throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed); - } - else - { - throw new NotSupportedException(SR.NotSupported_Reading); - } - } - if (position < 0) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); - } - - UInt32 sizeOfT = Marshal.AlignedSizeOf(); - - // only check position and ask for fewer Ts if count is too big - if (position >= _capacity) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); - } - - int n = count; - long spaceLeft = _capacity - position; - if (spaceLeft < 0) - { - n = 0; - } - else - { - ulong spaceNeeded = (ulong)(sizeOfT * count); - if ((ulong)spaceLeft < spaceNeeded) - { - n = (int)(spaceLeft / sizeOfT); - } - } - - _buffer.ReadArray((UInt64)(_offset + position), array, offset, n); - - return n; - } - - // ************** Write Methods ****************/ - - // The following 13 WriteXXX methods write a value of type XXX into unmanaged memory at 'positon'. - // The bounds of the unmanaged memory are checked against to ensure that there is enough - // space after 'position' to write a value of type XXX. XXX can be a bool, byte, char, decimal, - // double, short, int, long, sbyte, float, ushort, uint, or ulong. - - - public void Write(Int64 position, bool value) - { - int sizeOfType = sizeof(bool); - EnsureSafeToWrite(position, sizeOfType); - - byte b = (byte)(value ? 1 : 0); - InternalWrite(position, b); - } - - public void Write(Int64 position, byte value) - { - int sizeOfType = sizeof(byte); - EnsureSafeToWrite(position, sizeOfType); - - InternalWrite(position, value); - } - - public void Write(Int64 position, char value) - { - EnsureSafeToWrite(position, sizeof(char)); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - Unsafe.WriteUnaligned(pointer + _offset + position, value); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - - public void Write(Int64 position, Int16 value) - { - EnsureSafeToWrite(position, sizeof(Int16)); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - Unsafe.WriteUnaligned(pointer + _offset + position, value); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - - public void Write(Int64 position, Int32 value) - { - EnsureSafeToWrite(position, sizeof(Int32)); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - Unsafe.WriteUnaligned(pointer + _offset + position, value); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - public void Write(Int64 position, Int64 value) - { - EnsureSafeToWrite(position, sizeof(Int64)); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - Unsafe.WriteUnaligned(pointer + _offset + position, value); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - public void Write(Int64 position, Decimal value) - { - EnsureSafeToWrite(position, sizeof(Decimal)); - - unsafe - { - int* valuePtr = (int*)(&value); - int flags = *valuePtr; - int hi = *(valuePtr + 1); - int lo = *(valuePtr + 2); - int mid = *(valuePtr + 3); - - byte* pointer = null; - try - { - _buffer.AcquirePointer(ref pointer); - - Unsafe.WriteUnaligned(pointer + _offset + position, lo); - Unsafe.WriteUnaligned(pointer + _offset + position + 4, mid); - Unsafe.WriteUnaligned(pointer + _offset + position + 8, hi); - Unsafe.WriteUnaligned(pointer + _offset + position + 12, flags); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - public void Write(Int64 position, Single value) - { - EnsureSafeToWrite(position, sizeof(Single)); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - Unsafe.WriteUnaligned(pointer + _offset + position, value); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - public void Write(Int64 position, Double value) - { - EnsureSafeToWrite(position, sizeof(Double)); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - Unsafe.WriteUnaligned(pointer + _offset + position, value); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - [CLSCompliant(false)] - public void Write(Int64 position, SByte value) - { - EnsureSafeToWrite(position, sizeof(SByte)); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - *((SByte*)(pointer + _offset + position)) = value; - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - [CLSCompliant(false)] - public void Write(Int64 position, UInt16 value) - { - int sizeOfType = sizeof(UInt16); - EnsureSafeToWrite(position, sizeOfType); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - Unsafe.WriteUnaligned(pointer + _offset + position, value); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - [CLSCompliant(false)] - public void Write(Int64 position, UInt32 value) - { - EnsureSafeToWrite(position, sizeof(UInt32)); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - Unsafe.WriteUnaligned(pointer + _offset + position, value); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - [CLSCompliant(false)] - public void Write(Int64 position, UInt64 value) - { - EnsureSafeToWrite(position, sizeof(UInt64)); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - Unsafe.WriteUnaligned(pointer + _offset + position, value); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - // Writes the struct pointed to by ref value into unmanaged memory. Note that this method - // is most performant when used with medium to large sized structs (larger than 8 bytes - // though this is number is JIT and architecture dependent). As such, it is best to use - // the WriteX methods for small standard types such as ints, longs, bools, etc. - - public void Write(Int64 position, ref T structure) where T : struct - { - if (position < 0) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); - } - - if (!_isOpen) - { - throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed); - } - if (!CanWrite) - { - throw new NotSupportedException(SR.NotSupported_Writing); - } - - UInt32 sizeOfT = Marshal.SizeOfType(typeof(T)); - if (position > _capacity - sizeOfT) - { - if (position >= _capacity) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); - } - else - { - throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToWrite, typeof (T).FullName), nameof(position)); - } - } - - _buffer.Write((UInt64)(_offset + position), structure); - } - - // Writes 'count' structs of type T from 'array' (starting at 'offset') into unmanaged memory. - - - public void WriteArray(Int64 position, T[] array, Int32 offset, Int32 count) where T : struct - { - if (array == null) - { - throw new ArgumentNullException(nameof(array), "Buffer cannot be null."); - } - if (offset < 0) - { - throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (array.Length - offset < count) - { - throw new ArgumentException(SR.Argument_OffsetAndLengthOutOfBounds); - } - if (position < 0) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (position >= Capacity) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); - } - - if (!_isOpen) - { - throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed); - } - if (!CanWrite) - { - throw new NotSupportedException(SR.NotSupported_Writing); - } - - _buffer.WriteArray((UInt64)(_offset + position), array, offset, count); - } - - private byte InternalReadByte(Int64 position) - { - Debug.Assert(CanRead, "UMA not readable"); - Debug.Assert(position >= 0, "position less than 0"); - Debug.Assert(position <= _capacity - sizeof(byte), "position is greater than capacity - sizeof(byte)"); - - byte result; - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - result = *(pointer + _offset + position); - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - return result; - } - - private void InternalWrite(Int64 position, byte value) - { - Debug.Assert(CanWrite, "UMA not writable"); - Debug.Assert(position >= 0, "position less than 0"); - Debug.Assert(position <= _capacity - sizeof(byte), "position is greater than capacity - sizeof(byte)"); - - unsafe - { - byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - _buffer.AcquirePointer(ref pointer); - *(pointer + _offset + position) = value; - } - finally - { - if (pointer != null) - { - _buffer.ReleasePointer(); - } - } - } - } - - private void EnsureSafeToRead(Int64 position, int sizeOfType) - { - if (!_isOpen) - { - throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed); - } - if (!CanRead) - { - throw new NotSupportedException(SR.NotSupported_Reading); - } - if (position < 0) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (position > _capacity - sizeOfType) - { - if (position >= _capacity) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); - } - else - { - throw new ArgumentException(SR.Argument_NotEnoughBytesToRead, nameof(position)); - } - } - } - - private void EnsureSafeToWrite(Int64 position, int sizeOfType) - { - if (!_isOpen) - { - throw new ObjectDisposedException("UnmanagedMemoryAccessor", SR.ObjectDisposed_ViewAccessorClosed); - } - if (!CanWrite) - { - throw new NotSupportedException(SR.NotSupported_Writing); - } - if (position < 0) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (position > _capacity - sizeOfType) - { - if (position >= _capacity) - { - throw new ArgumentOutOfRangeException(nameof(position), SR.ArgumentOutOfRange_PositionLessThanCapacityRequired); - } - else - { - throw new ArgumentException(SR.Format(SR.Argument_NotEnoughBytesToWrite, nameof(Byte)), nameof(position)); - } - } - } - } -} diff --git a/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs b/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs index efa5125..98b33e3 100644 --- a/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs +++ b/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs @@ -256,35 +256,6 @@ namespace System.Runtime.InteropServices return SizeOf(typeof(T)); } - /// - /// Returns the aligned size of an instance of a value type. - /// - /// Provide a value type to figure out its size - /// The aligned size of T in bytes. - internal static uint AlignedSizeOf() where T : struct - { - uint size = SizeOfType(typeof(T)); - if (size == 1 || size == 2) - { - return size; - } - if (IntPtr.Size == 8 && size == 4) - { - return size; - } - return AlignedSizeOfType(typeof(T)); - } - - // Type must be a value type with no object reference fields. We only - // assert this, due to the lack of a suitable generic constraint. - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern uint SizeOfType(Type type); - - // Type must be a value type with no object reference fields. We only - // assert this, due to the lack of a suitable generic constraint. - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern uint AlignedSizeOfType(Type type); - [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern int SizeOfHelper(Type t, bool throwIfNotMarshalable); diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SafeBuffer.cs b/src/mscorlib/src/System/Runtime/InteropServices/SafeBuffer.cs index 4f97875..0447ea5 100644 --- a/src/mscorlib/src/System/Runtime/InteropServices/SafeBuffer.cs +++ b/src/mscorlib/src/System/Runtime/InteropServices/SafeBuffer.cs @@ -129,7 +129,7 @@ namespace System.Runtime.InteropServices [CLSCompliant(false)] public void Initialize(uint numElements) where T : struct { - Initialize(numElements, Marshal.AlignedSizeOf()); + Initialize(numElements, AlignedSizeOf()); } // Callers should ensure that they check whether the pointer ref param @@ -198,7 +198,7 @@ namespace System.Runtime.InteropServices if (_numBytes == Uninitialized) throw NotInitialized(); - uint sizeofT = Marshal.SizeOfType(typeof(T)); + uint sizeofT = SizeOf(); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, sizeofT); @@ -236,8 +236,8 @@ namespace System.Runtime.InteropServices if (_numBytes == Uninitialized) throw NotInitialized(); - uint sizeofT = Marshal.SizeOfType(typeof(T)); - uint alignedSizeofT = Marshal.AlignedSizeOf(); + uint sizeofT = SizeOf(); + uint alignedSizeofT = AlignedSizeOf(); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, checked((ulong)(alignedSizeofT * count))); @@ -271,7 +271,7 @@ namespace System.Runtime.InteropServices if (_numBytes == Uninitialized) throw NotInitialized(); - uint sizeofT = Marshal.SizeOfType(typeof(T)); + uint sizeofT = SizeOf(); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, sizeofT); @@ -306,8 +306,8 @@ namespace System.Runtime.InteropServices if (_numBytes == Uninitialized) throw NotInitialized(); - uint sizeofT = Marshal.SizeOfType(typeof(T)); - uint alignedSizeofT = Marshal.AlignedSizeOf(); + uint sizeofT = SizeOf(); + uint alignedSizeofT = AlignedSizeOf(); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, checked((ulong)(alignedSizeofT * count))); @@ -381,5 +381,44 @@ namespace System.Runtime.InteropServices [MethodImpl(MethodImplOptions.InternalCall)] private static extern void StructureToPtrNative(/*ref T*/ TypedReference structure, byte* ptr, uint sizeofT); + + /// + /// Returns the aligned size of an instance of a value type. + /// + /// Provide a value type to figure out its size + /// The aligned size of T in bytes. + internal static uint SizeOf() where T : struct + { + return SizeOfType(typeof(T)); + } + + /// + /// Returns the aligned size of an instance of a value type. + /// + /// Provide a value type to figure out its size + /// The aligned size of T in bytes. + internal static uint AlignedSizeOf() where T : struct + { + uint size = SizeOfType(typeof(T)); + if (size == 1 || size == 2) + { + return size; + } + if (IntPtr.Size == 8 && size == 4) + { + return size; + } + return AlignedSizeOfType(typeof(T)); + } + + // Type must be a value type with no object reference fields. We only + // assert this, due to the lack of a suitable generic constraint. + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern uint SizeOfType(Type type); + + // Type must be a value type with no object reference fields. We only + // assert this, due to the lack of a suitable generic constraint. + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern uint AlignedSizeOfType(Type type); } } diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h index 4ee9826..207e89a 100644 --- a/src/vm/ecalllist.h +++ b/src/vm/ecalllist.h @@ -201,6 +201,8 @@ FCFuncEnd() FCFuncStart(gSafeBufferFuncs) FCFuncElement("PtrToStructureNative", SafeBuffer::PtrToStructure) FCFuncElement("StructureToPtrNative", SafeBuffer::StructureToPtr) + FCFuncElement("SizeOfType", SafeBuffer::SizeOfType) + FCFuncElement("AlignedSizeOfType", SafeBuffer::AlignedSizeOfType) FCFuncEnd() FCFuncStart(gTypedReferenceFuncs) @@ -894,8 +896,6 @@ FCFuncStart(gInteropMarshalFuncs) QCFuncElement("GetHINSTANCE", COMModule::GetHINSTANCE) FCFuncElement("OffsetOfHelper", MarshalNative::OffsetOfHelper) - FCFuncElement("SizeOfType", SafeBuffer::SizeOfType) - FCFuncElement("AlignedSizeOfType", SafeBuffer::AlignedSizeOfType) QCFuncElement("InternalPrelink", MarshalNative::Prelink) FCFuncElement("CopyToNative", MarshalNative::CopyToNative)