diff options
Diffstat (limited to 'src/mscorlib/src/System/IO/UnmanagedMemoryAccessor.cs')
-rw-r--r-- | src/mscorlib/src/System/IO/UnmanagedMemoryAccessor.cs | 215 |
1 files changed, 129 insertions, 86 deletions
diff --git a/src/mscorlib/src/System/IO/UnmanagedMemoryAccessor.cs b/src/mscorlib/src/System/IO/UnmanagedMemoryAccessor.cs index ea70057217..4208ebfb6d 100644 --- a/src/mscorlib/src/System/IO/UnmanagedMemoryAccessor.cs +++ b/src/mscorlib/src/System/IO/UnmanagedMemoryAccessor.cs @@ -19,6 +19,7 @@ using System.Runtime.ConstrainedExecution; using System.Runtime.Versioning; using System.Security.Permissions; using Microsoft.Win32.SafeHandles; +using System.Diagnostics; using System.Diagnostics.Contracts; namespace System.IO { @@ -28,7 +29,6 @@ namespace System.IO { /// this gives better throughput; benchmarks showed about 12-15% better. public class UnmanagedMemoryAccessor : IDisposable { - [System.Security.SecurityCritical] // auto-generated private SafeBuffer _buffer; private Int64 _offset; [ContractPublicPropertyName("Capacity")] @@ -46,35 +46,29 @@ namespace System.IO { // <SecurityKernel Critical="True" Ring="1"> // <ReferencesCritical Name="Method: Initialize(SafeBuffer, Int64, Int64, FileAccess):Void" Ring="1" /> // </SecurityKernel> - [System.Security.SecuritySafeCritical] public UnmanagedMemoryAccessor(SafeBuffer buffer, Int64 offset, Int64 capacity) { Initialize(buffer, offset, capacity, FileAccess.Read); } - [System.Security.SecuritySafeCritical] // auto-generated public UnmanagedMemoryAccessor(SafeBuffer buffer, Int64 offset, Int64 capacity, FileAccess access) { Initialize(buffer, offset, capacity, access); } - [System.Security.SecuritySafeCritical] // auto-generated -#pragma warning disable 618 - [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] -#pragma warning restore 618 protected void Initialize(SafeBuffer buffer, Int64 offset, Int64 capacity, FileAccess access) { if (buffer == null) { - throw new ArgumentNullException("buffer"); + throw new ArgumentNullException(nameof(buffer)); } if (offset < 0) { - throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(offset), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (capacity < 0) { - throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(capacity), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (buffer.ByteLength < (UInt64)(offset + capacity)) { throw new ArgumentException(Environment.GetResourceString("Argument_OffsetAndCapacityOutOfBounds")); } if (access < FileAccess.Read || access > FileAccess.ReadWrite) { - throw new ArgumentOutOfRangeException("access"); + throw new ArgumentOutOfRangeException(nameof(access)); } Contract.EndContractBlock(); @@ -155,7 +149,6 @@ namespace System.IO { return InternalReadByte(position); } - [System.Security.SecuritySafeCritical] // auto-generated public char ReadChar(Int64 position) { int sizeOfType = sizeof(char); EnsureSafeToRead(position, sizeOfType); @@ -192,7 +185,6 @@ namespace System.IO { } // See comment above. - [System.Security.SecuritySafeCritical] public Int16 ReadInt16(Int64 position) { int sizeOfType = sizeof(Int16); EnsureSafeToRead(position, sizeOfType); @@ -229,7 +221,6 @@ namespace System.IO { } - [System.Security.SecuritySafeCritical] // auto-generated public Int32 ReadInt32(Int64 position) { int sizeOfType = sizeof(Int32); EnsureSafeToRead(position, sizeOfType); @@ -264,7 +255,6 @@ namespace System.IO { return result; } - [System.Security.SecuritySafeCritical] // auto-generated public Int64 ReadInt64(Int64 position) { int sizeOfType = sizeof(Int64); EnsureSafeToRead(position, sizeOfType); @@ -301,18 +291,63 @@ namespace System.IO { return result; } - [System.Security.SecuritySafeCritical] // auto-generated + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe Int32 UnsafeReadInt32(byte* pointer) + { + Int32 result; + // check if pointer is aligned + if (((int)pointer & (sizeof(Int32) - 1)) == 0) + { + result = *((Int32*)pointer); + } + else + { + result = (Int32)(*(pointer) | *(pointer + 1) << 8 | *(pointer + 2) << 16 | *(pointer + 3) << 24); + } + + return result; + } public Decimal ReadDecimal(Int64 position) { + const int ScaleMask = 0x00FF0000; + const int SignMask = unchecked((int)0x80000000); + int sizeOfType = sizeof(Decimal); EnsureSafeToRead(position, sizeOfType); - int[] decimalArray = new int[4]; - ReadArray<int>(position, decimalArray, 0, decimalArray.Length); + unsafe + { + byte* pointer = null; + try + { + _buffer.AcquirePointer(ref pointer); + pointer += (_offset + position); - return new Decimal(decimalArray); + int lo = UnsafeReadInt32(pointer); + int mid = UnsafeReadInt32(pointer + 4); + int hi = UnsafeReadInt32(pointer + 8); + int flags = UnsafeReadInt32(pointer + 12); + + // Check for invalid Decimal values + if (!((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16))) + { + throw new ArgumentException(Environment.GetResourceString("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); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } } - [System.Security.SecuritySafeCritical] // auto-generated public Single ReadSingle(Int64 position) { int sizeOfType = sizeof(Single); EnsureSafeToRead(position, sizeOfType); @@ -329,7 +364,7 @@ namespace System.IO { // check if pointer is aligned if (((int)pointer & (sizeOfType - 1)) == 0) { #endif - result = *((Single*)(pointer)); + result = BitConverter.Int32BitsToSingle(*((int*)(pointer))); #if ALIGN_ACCESS } else { @@ -348,7 +383,6 @@ namespace System.IO { return result; } - [System.Security.SecuritySafeCritical] // auto-generated public Double ReadDouble(Int64 position) { int sizeOfType = sizeof(Double); EnsureSafeToRead(position, sizeOfType); @@ -365,7 +399,7 @@ namespace System.IO { // check if pointer is aligned if (((int)pointer & (sizeOfType - 1)) == 0) { #endif - result = *((Double*)(pointer)); + result = BitConverter.Int64BitsToDouble(*((long*)(pointer))); #if ALIGN_ACCESS } else { @@ -388,7 +422,6 @@ namespace System.IO { return result; } - [System.Security.SecuritySafeCritical] // auto-generated [CLSCompliant(false)] public SByte ReadSByte(Int64 position) { int sizeOfType = sizeof(SByte); @@ -413,7 +446,6 @@ namespace System.IO { return result; } - [System.Security.SecuritySafeCritical] // auto-generated [CLSCompliant(false)] public UInt16 ReadUInt16(Int64 position) { int sizeOfType = sizeof(UInt16); @@ -450,7 +482,6 @@ namespace System.IO { return result; } - [System.Security.SecuritySafeCritical] // auto-generated [CLSCompliant(false)] public UInt32 ReadUInt32(Int64 position) { int sizeOfType = sizeof(UInt32); @@ -487,7 +518,6 @@ namespace System.IO { return result; } - [System.Security.SecuritySafeCritical] // auto-generated [CLSCompliant(false)] public UInt64 ReadUInt64(Int64 position) { int sizeOfType = sizeof(UInt64); @@ -540,10 +570,9 @@ namespace System.IO { // such, it is best to use the ReadXXX methods for small standard types such as ints, longs, // bools, etc. - [System.Security.SecurityCritical] // auto-generated_required public void Read<T>(Int64 position, out T structure) where T : struct { if (position < 0) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } Contract.EndContractBlock(); @@ -557,10 +586,10 @@ namespace System.IO { UInt32 sizeOfT = Marshal.SizeOfType(typeof(T)); if (position > _capacity - sizeOfT) { if (position >= _capacity) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); } else { - throw new ArgumentException(Environment.GetResourceString("Argument_NotEnoughBytesToRead", typeof(T).FullName), "position"); + throw new ArgumentException(Environment.GetResourceString("Argument_NotEnoughBytesToRead", typeof(T).FullName), nameof(position)); } } @@ -573,16 +602,15 @@ namespace System.IO { // struct that contains reference members will most likely cause the runtime to AV. This // is consistent with Marshal.PtrToStructure. - [System.Security.SecurityCritical] // auto-generated_required public int ReadArray<T>(Int64 position, T[] array, Int32 offset, Int32 count) where T : struct { if (array == null) { - throw new ArgumentNullException("array", "Buffer cannot be null."); + throw new ArgumentNullException(nameof(array), "Buffer cannot be null."); } if (offset < 0) { - throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(offset), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (count < 0) { - throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (array.Length - offset < count) { throw new ArgumentException(Environment.GetResourceString("Argument_OffsetAndLengthOutOfBounds")); @@ -597,14 +625,14 @@ namespace System.IO { } } if (position < 0) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } UInt32 sizeOfT = Marshal.AlignedSizeOf<T>(); // only check position and ask for fewer Ts if count is too big if (position >= _capacity) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); } int n = count; @@ -647,7 +675,6 @@ namespace System.IO { InternalWrite(position, value); } - [System.Security.SecuritySafeCritical] // auto-generated public void Write(Int64 position, char value) { int sizeOfType = sizeof(char); EnsureSafeToWrite(position, sizeOfType); @@ -682,7 +709,6 @@ namespace System.IO { } - [System.Security.SecuritySafeCritical] // auto-generated public void Write(Int64 position, Int16 value) { int sizeOfType = sizeof(Int16); EnsureSafeToWrite(position, sizeOfType); @@ -716,7 +742,6 @@ namespace System.IO { } - [System.Security.SecuritySafeCritical] // auto-generated public void Write(Int64 position, Int32 value) { int sizeOfType = sizeof(Int32); EnsureSafeToWrite(position, sizeOfType); @@ -751,7 +776,6 @@ namespace System.IO { } } - [System.Security.SecuritySafeCritical] // auto-generated public void Write(Int64 position, Int64 value) { int sizeOfType = sizeof(Int64); EnsureSafeToWrite(position, sizeOfType); @@ -789,28 +813,56 @@ namespace System.IO { } } - [System.Security.SecuritySafeCritical] // auto-generated + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe void UnsafeWriteInt32(byte* pointer, Int32 value) + { + // check if pointer is aligned + if (((int)pointer & (sizeof(Int32) - 1)) == 0) + { + *((Int32*)pointer) = value; + } + else + { + *(pointer) = (byte)value; + *(pointer + 1) = (byte)(value >> 8); + *(pointer + 2) = (byte)(value >> 16); + *(pointer + 3) = (byte)(value >> 24); + } + } + public void Write(Int64 position, Decimal value) { int sizeOfType = sizeof(Decimal); EnsureSafeToWrite(position, sizeOfType); - byte[] decimalArray = new byte[16]; - Decimal.GetBytes(value, decimalArray); + unsafe + { + byte* pointer = null; + try + { + _buffer.AcquirePointer(ref pointer); + pointer += (_offset + position); - int[] bits = new int[4]; - int flags = ((int)decimalArray[12]) | ((int)decimalArray[13] << 8) | ((int)decimalArray[14] << 16) | ((int)decimalArray[15] << 24); - int lo = ((int)decimalArray[0]) | ((int)decimalArray[1] << 8) | ((int)decimalArray[2] << 16) | ((int)decimalArray[3] << 24); - int mid = ((int)decimalArray[4]) | ((int)decimalArray[5] << 8) | ((int)decimalArray[6] << 16) | ((int)decimalArray[7] << 24); - int hi = ((int)decimalArray[8]) | ((int)decimalArray[9] << 8) | ((int)decimalArray[10] << 16) | ((int)decimalArray[11] << 24); - bits[0] = lo; - bits[1] = mid; - bits[2] = hi; - bits[3] = flags; + int* valuePtr = (int*)(&value); + int flags = *valuePtr; + int hi = *(valuePtr + 1); + int lo = *(valuePtr + 2); + int mid = *(valuePtr + 3); - WriteArray<int>(position, bits, 0, bits.Length); + UnsafeWriteInt32(pointer, lo); + UnsafeWriteInt32(pointer + 4, mid); + UnsafeWriteInt32(pointer + 8, hi); + UnsafeWriteInt32(pointer + 12, flags); + } + finally + { + if (pointer != null) + { + _buffer.ReleasePointer(); + } + } + } } - [System.Security.SecuritySafeCritical] // auto-generated public void Write(Int64 position, Single value) { int sizeOfType = sizeof(Single); EnsureSafeToWrite(position, sizeOfType); @@ -825,7 +877,7 @@ namespace System.IO { // check if pointer is aligned if (((int)pointer & (sizeOfType - 1)) == 0) { #endif - *((Single*)pointer) = value; + *((int*)pointer) = BitConverter.SingleToInt32Bits(value); #if ALIGN_ACCESS } else { @@ -846,7 +898,6 @@ namespace System.IO { } } - [System.Security.SecuritySafeCritical] // auto-generated public void Write(Int64 position, Double value) { int sizeOfType = sizeof(Double); EnsureSafeToWrite(position, sizeOfType); @@ -861,7 +912,7 @@ namespace System.IO { // check if pointer is aligned if (((int)pointer & (sizeOfType - 1)) == 0) { #endif - *((Double*)pointer) = value; + *((long*)pointer) = BitConverter.DoubleToInt64Bits(value); #if ALIGN_ACCESS } else { @@ -886,7 +937,6 @@ namespace System.IO { } } - [System.Security.SecuritySafeCritical] // auto-generated [CLSCompliant(false)] public void Write(Int64 position, SByte value) { int sizeOfType = sizeof(SByte); @@ -908,7 +958,6 @@ namespace System.IO { } } - [System.Security.SecuritySafeCritical] // auto-generated [CLSCompliant(false)] public void Write(Int64 position, UInt16 value) { int sizeOfType = sizeof(UInt16); @@ -942,7 +991,6 @@ namespace System.IO { } } - [System.Security.SecuritySafeCritical] // auto-generated [CLSCompliant(false)] public void Write(Int64 position, UInt32 value) { int sizeOfType = sizeof(UInt32); @@ -979,7 +1027,6 @@ namespace System.IO { } } - [System.Security.SecuritySafeCritical] // auto-generated [CLSCompliant(false)] public void Write(Int64 position, UInt64 value) { int sizeOfType = sizeof(UInt64); @@ -1024,10 +1071,9 @@ namespace System.IO { // 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. - [System.Security.SecurityCritical] // auto-generated_required public void Write<T>(Int64 position, ref T structure) where T : struct { if (position < 0) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } Contract.EndContractBlock(); @@ -1041,10 +1087,10 @@ namespace System.IO { UInt32 sizeOfT = Marshal.SizeOfType(typeof(T)); if (position > _capacity - sizeOfT) { if (position >= _capacity) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); } else { - throw new ArgumentException(Environment.GetResourceString("Argument_NotEnoughBytesToWrite", typeof(T).FullName), "position"); + throw new ArgumentException(Environment.GetResourceString("Argument_NotEnoughBytesToWrite", typeof(T).FullName), nameof(position)); } } @@ -1054,25 +1100,24 @@ namespace System.IO { // Writes 'count' structs of type T from 'array' (starting at 'offset') into unmanaged memory. - [System.Security.SecurityCritical] // auto-generated_required public void WriteArray<T>(Int64 position, T[] array, Int32 offset, Int32 count) where T : struct { if (array == null) { - throw new ArgumentNullException("array", "Buffer cannot be null."); + throw new ArgumentNullException(nameof(array), "Buffer cannot be null."); } if (offset < 0) { - throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(offset), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (count < 0) { - throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (array.Length - offset < count) { throw new ArgumentException(Environment.GetResourceString("Argument_OffsetAndLengthOutOfBounds")); } if (position < 0) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (position >= Capacity) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); } Contract.EndContractBlock(); @@ -1086,11 +1131,10 @@ namespace System.IO { _buffer.WriteArray<T>((UInt64)(_offset + position), array, offset, count); } - [System.Security.SecuritySafeCritical] // auto-generated private byte InternalReadByte(Int64 position) { - Contract.Assert(CanRead, "UMA not readable"); - Contract.Assert(position >= 0, "position less than 0"); - Contract.Assert(position <= _capacity - sizeof(byte), "position is greater than capacity - sizeof(byte)"); + 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 { @@ -1109,11 +1153,10 @@ namespace System.IO { return result; } - [System.Security.SecuritySafeCritical] // auto-generated private void InternalWrite(Int64 position, byte value) { - Contract.Assert(CanWrite, "UMA not writeable"); - Contract.Assert(position >= 0, "position less than 0"); - Contract.Assert(position <= _capacity - sizeof(byte), "position is greater than capacity - sizeof(byte)"); + 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; @@ -1138,15 +1181,15 @@ namespace System.IO { throw new NotSupportedException(Environment.GetResourceString("NotSupported_Reading")); } if (position < 0) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } Contract.EndContractBlock(); if (position > _capacity - sizeOfType) { if (position >= _capacity) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); } else { - throw new ArgumentException(Environment.GetResourceString("Argument_NotEnoughBytesToRead"), "position"); + throw new ArgumentException(Environment.GetResourceString("Argument_NotEnoughBytesToRead"), nameof(position)); } } } @@ -1159,15 +1202,15 @@ namespace System.IO { throw new NotSupportedException(Environment.GetResourceString("NotSupported_Writing")); } if (position < 0) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } Contract.EndContractBlock(); if (position > _capacity - sizeOfType) { if (position >= _capacity) { - throw new ArgumentOutOfRangeException("position", Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); + throw new ArgumentOutOfRangeException(nameof(position), Environment.GetResourceString("ArgumentOutOfRange_PositionLessThanCapacityRequired")); } else { - throw new ArgumentException(Environment.GetResourceString("Argument_NotEnoughBytesToWrite", "Byte"), "position"); + throw new ArgumentException(Environment.GetResourceString("Argument_NotEnoughBytesToWrite", nameof(Byte)), nameof(position)); } } } |