From 0bb37fde2befd38d4a082d5c0eb269ae3e35b546 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Tue, 2 Jan 2018 02:24:42 +0000 Subject: [PATCH] Encoding: Don't alloc for zero length array (#13794) --- .../shared/System/Text/ASCIIEncoding.cs | 21 ++++--------- src/mscorlib/shared/System/Text/DecoderNLS.cs | 30 ++++--------------- src/mscorlib/shared/System/Text/EncoderNLS.cs | 27 ++++------------- .../shared/System/Text/EncodingNLS.cs | 21 ++++--------- .../shared/System/Text/UTF32Encoding.cs | 19 +++--------- .../shared/System/Text/UTF7Encoding.cs | 19 +++--------- .../shared/System/Text/UTF8Encoding.cs | 19 +++--------- .../shared/System/Text/UnicodeEncoding.cs | 19 +++--------- 8 files changed, 38 insertions(+), 137 deletions(-) diff --git a/src/mscorlib/shared/System/Text/ASCIIEncoding.cs b/src/mscorlib/shared/System/Text/ASCIIEncoding.cs index 2d2bf205ae7e..e89943a19253 100644 --- a/src/mscorlib/shared/System/Text/ASCIIEncoding.cs +++ b/src/mscorlib/shared/System/Text/ASCIIEncoding.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; +using System.Runtime.InteropServices; namespace System.Text { @@ -130,11 +131,7 @@ public override unsafe int GetByteCount(char* chars, int count) int byteCount = bytes.Length - byteIndex; - // Fixed doesn't like empty byte arrays - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = chars) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -168,18 +165,14 @@ public override unsafe int GetByteCount(char* chars, int count) if (byteIndex < 0 || byteIndex > bytes.Length) throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index); - // If nothing to encode return 0, avoid fixed problem + // If nothing to encode return 0 if (charCount == 0) return 0; // Just call pointer version int byteCount = bytes.Length - byteIndex; - // Fixed doesn't like empty byte arrays - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = chars) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) // Remember that byteCount is # to decode, not size of array. return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -275,11 +268,7 @@ public override unsafe int GetCharCount(byte* bytes, int count) // Just call pointer version int charCount = chars.Length - charIndex; - // Fixed doesn't like empty char arrays - if (chars.Length == 0) - chars = new char[1]; - - fixed (byte* pBytes = bytes) fixed (char* pChars = &chars[0]) + fixed (byte* pBytes = bytes) fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) // Remember that charCount is # to decode, not size of array return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null); } diff --git a/src/mscorlib/shared/System/Text/DecoderNLS.cs b/src/mscorlib/shared/System/Text/DecoderNLS.cs index 098730eed436..ee88c22f9d0e 100644 --- a/src/mscorlib/shared/System/Text/DecoderNLS.cs +++ b/src/mscorlib/shared/System/Text/DecoderNLS.cs @@ -5,6 +5,7 @@ using System.Runtime.Serialization; using System.Text; using System; +using System.Runtime.InteropServices; namespace System.Text { @@ -66,13 +67,8 @@ public override unsafe int GetCharCount(byte[] bytes, int index, int count, bool throw new ArgumentOutOfRangeException(nameof(bytes), SR.ArgumentOutOfRange_IndexCountBuffer); - - // Avoid null fixed problem - if (bytes.Length == 0) - bytes = new byte[1]; - // Just call pointer version - fixed (byte* pBytes = &bytes[0]) + fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) return GetCharCount(pBytes + index, count, flush); } @@ -121,18 +117,11 @@ public unsafe override int GetCharCount(byte* bytes, int count, bool flush) throw new ArgumentOutOfRangeException(nameof(charIndex), SR.ArgumentOutOfRange_Index); - - // Avoid empty input fixed problem - if (bytes.Length == 0) - bytes = new byte[1]; - int charCount = chars.Length - charIndex; - if (chars.Length == 0) - chars = new char[1]; // Just call pointer version - fixed (byte* pBytes = &bytes[0]) - fixed (char* pChars = &chars[0]) + fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) + fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) // Remember that charCount is # to decode, not size of array return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, flush); @@ -185,17 +174,10 @@ public unsafe override int GetCharCount(byte* bytes, int count, bool flush) throw new ArgumentOutOfRangeException(nameof(chars), SR.ArgumentOutOfRange_IndexCountBuffer); - - // Avoid empty input problem - if (bytes.Length == 0) - bytes = new byte[1]; - if (chars.Length == 0) - chars = new char[1]; - // Just call the pointer version (public overrides can't do this) - fixed (byte* pBytes = &bytes[0]) + fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) { - fixed (char* pChars = &chars[0]) + fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) { Convert(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, flush, out bytesUsed, out charsUsed, out completed); diff --git a/src/mscorlib/shared/System/Text/EncoderNLS.cs b/src/mscorlib/shared/System/Text/EncoderNLS.cs index f8ff86d98598..e83666f7a3f1 100644 --- a/src/mscorlib/shared/System/Text/EncoderNLS.cs +++ b/src/mscorlib/shared/System/Text/EncoderNLS.cs @@ -4,6 +4,7 @@ using System.Text; using System; +using System.Runtime.InteropServices; namespace System.Text { @@ -63,13 +64,9 @@ public override unsafe int GetByteCount(char[] chars, int index, int count, bool throw new ArgumentOutOfRangeException(nameof(chars), SR.ArgumentOutOfRange_IndexCountBuffer); - // Avoid empty input problem - if (chars.Length == 0) - chars = new char[1]; - // Just call the pointer version int result = -1; - fixed (char* pChars = &chars[0]) + fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) { result = GetByteCount(pChars + index, count, flush); } @@ -112,16 +109,11 @@ public unsafe override int GetByteCount(char* chars, int count, bool flush) throw new ArgumentOutOfRangeException(nameof(byteIndex), SR.ArgumentOutOfRange_Index); - if (chars.Length == 0) - chars = new char[1]; - int byteCount = bytes.Length - byteIndex; - if (bytes.Length == 0) - bytes = new byte[1]; // Just call pointer version - fixed (char* pChars = &chars[0]) - fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) + fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) // Remember that charCount is # to decode, not size of array. return GetBytes(pChars + charIndex, charCount, @@ -171,17 +163,10 @@ public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int throw new ArgumentOutOfRangeException(nameof(bytes), SR.ArgumentOutOfRange_IndexCountBuffer); - - // Avoid empty input problem - if (chars.Length == 0) - chars = new char[1]; - if (bytes.Length == 0) - bytes = new byte[1]; - // Just call the pointer version (can't do this for non-msft encoders) - fixed (char* pChars = &chars[0]) + fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) { - fixed (byte* pBytes = &bytes[0]) + fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) { Convert(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, flush, out charsUsed, out bytesUsed, out completed); diff --git a/src/mscorlib/shared/System/Text/EncodingNLS.cs b/src/mscorlib/shared/System/Text/EncodingNLS.cs index 5059407ab9de..d5de9e553a53 100644 --- a/src/mscorlib/shared/System/Text/EncodingNLS.cs +++ b/src/mscorlib/shared/System/Text/EncodingNLS.cs @@ -5,6 +5,7 @@ using System; using System.Collections; using System.Globalization; +using System.Runtime.InteropServices; using System.Threading; namespace System.Text @@ -107,11 +108,7 @@ public override unsafe int GetByteCount(char* chars, int count) int byteCount = bytes.Length - byteIndex; - // Fixed doesn't like empty arrays - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = s) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = s) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -151,13 +148,9 @@ public override unsafe int GetByteCount(char* chars, int count) // Just call pointer version int byteCount = bytes.Length - byteIndex; - // Fixed doesn't like empty arrays - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = chars) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) // Remember that byteCount is # to decode, not size of array. - return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); + return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) @@ -245,11 +238,7 @@ public override unsafe int GetCharCount(byte* bytes, int count) // Just call pointer version int charCount = chars.Length - charIndex; - // Fixed doesn't like empty arrays - if (chars.Length == 0) - chars = new char[1]; - - fixed (byte* pBytes = bytes) fixed (char* pChars = &chars[0]) + fixed (byte* pBytes = bytes) fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) // Remember that charCount is # to decode, not size of array return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null); } diff --git a/src/mscorlib/shared/System/Text/UTF32Encoding.cs b/src/mscorlib/shared/System/Text/UTF32Encoding.cs index a666c25627e9..7828775ea05d 100644 --- a/src/mscorlib/shared/System/Text/UTF32Encoding.cs +++ b/src/mscorlib/shared/System/Text/UTF32Encoding.cs @@ -9,6 +9,7 @@ using System; using System.Diagnostics; using System.Globalization; +using System.Runtime.InteropServices; namespace System.Text { @@ -174,11 +175,7 @@ public override unsafe int GetByteCount(char* chars, int count) int byteCount = bytes.Length - byteIndex; - // Fix our input array if 0 length because fixed doesn't like 0 length arrays - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = s) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = s) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -219,11 +216,7 @@ public override unsafe int GetByteCount(char* chars, int count) // Just call pointer version int byteCount = bytes.Length - byteIndex; - // Fix our input array if 0 length because fixed doesn't like 0 length arrays - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = chars) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) // Remember that byteCount is # to decode, not size of array. return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -319,11 +312,7 @@ public override unsafe int GetCharCount(byte* bytes, int count) // Just call pointer version int charCount = chars.Length - charIndex; - // Fix our input array if 0 length because fixed doesn't like 0 length arrays - if (chars.Length == 0) - chars = new char[1]; - - fixed (byte* pBytes = bytes) fixed (char* pChars = &chars[0]) + fixed (byte* pBytes = bytes) fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) // Remember that charCount is # to decode, not size of array return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null); } diff --git a/src/mscorlib/shared/System/Text/UTF7Encoding.cs b/src/mscorlib/shared/System/Text/UTF7Encoding.cs index 78813649b673..0246c28915f7 100644 --- a/src/mscorlib/shared/System/Text/UTF7Encoding.cs +++ b/src/mscorlib/shared/System/Text/UTF7Encoding.cs @@ -8,6 +8,7 @@ using System; using System.Diagnostics; +using System.Runtime.InteropServices; namespace System.Text { @@ -204,11 +205,7 @@ public override unsafe int GetByteCount(char* chars, int count) int byteCount = bytes.Length - byteIndex; - // Fixed doesn't like empty arrays - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = s) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = s) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -249,11 +246,7 @@ public override unsafe int GetByteCount(char* chars, int count) // Just call pointer version int byteCount = bytes.Length - byteIndex; - // Fixed doesn't like empty arrays - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = chars) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) // Remember that byteCount is # to decode, not size of array. return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -349,11 +342,7 @@ public override unsafe int GetCharCount(byte* bytes, int count) // Just call pointer version int charCount = chars.Length - charIndex; - // Fixed doesn't like empty arrays - if (chars.Length == 0) - chars = new char[1]; - - fixed (byte* pBytes = bytes) fixed (char* pChars = &chars[0]) + fixed (byte* pBytes = bytes) fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) // Remember that charCount is # to decode, not size of array return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null); } diff --git a/src/mscorlib/shared/System/Text/UTF8Encoding.cs b/src/mscorlib/shared/System/Text/UTF8Encoding.cs index e5544c519499..a89af8edb0b2 100644 --- a/src/mscorlib/shared/System/Text/UTF8Encoding.cs +++ b/src/mscorlib/shared/System/Text/UTF8Encoding.cs @@ -17,6 +17,7 @@ using System; using System.Diagnostics; using System.Globalization; +using System.Runtime.InteropServices; namespace System.Text { @@ -201,11 +202,7 @@ public override unsafe int GetByteCount(char* chars, int count) int byteCount = bytes.Length - byteIndex; - // Fixed doesn't like 0 length arrays. - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = s) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = s) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -246,11 +243,7 @@ public override unsafe int GetByteCount(char* chars, int count) // Just call pointer version int byteCount = bytes.Length - byteIndex; - // Fixed doesn't like 0 length arrays. - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = chars) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) // Remember that byteCount is # to decode, not size of array. return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -346,11 +339,7 @@ public override unsafe int GetCharCount(byte* bytes, int count) // Just call pointer version int charCount = chars.Length - charIndex; - // Fixed doesn't like 0 length arrays. - if (chars.Length == 0) - chars = new char[1]; - - fixed (byte* pBytes = bytes) fixed (char* pChars = &chars[0]) + fixed (byte* pBytes = bytes) fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) // Remember that charCount is # to decode, not size of array return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null); } diff --git a/src/mscorlib/shared/System/Text/UnicodeEncoding.cs b/src/mscorlib/shared/System/Text/UnicodeEncoding.cs index a5b89a66669e..342bf53d62f5 100644 --- a/src/mscorlib/shared/System/Text/UnicodeEncoding.cs +++ b/src/mscorlib/shared/System/Text/UnicodeEncoding.cs @@ -9,6 +9,7 @@ using System; using System.Globalization; using System.Diagnostics; +using System.Runtime.InteropServices; namespace System.Text { @@ -160,11 +161,7 @@ public override unsafe int GetByteCount(char* chars, int count) int byteCount = bytes.Length - byteIndex; - // Fixed doesn't like 0 length arrays. - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = s) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = s) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -205,11 +202,7 @@ public override unsafe int GetByteCount(char* chars, int count) // Just call pointer version int byteCount = bytes.Length - byteIndex; - // Fixed doesn't like 0 length arrays. - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = chars) fixed (byte* pBytes = &bytes[0]) + fixed (char* pChars = chars) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span)bytes)) // Remember that byteCount is # to decode, not size of array. return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); } @@ -305,11 +298,7 @@ public override unsafe int GetCharCount(byte* bytes, int count) // Just call pointer version int charCount = chars.Length - charIndex; - // Fixed doesn't like 0 length arrays. - if (chars.Length == 0) - chars = new char[1]; - - fixed (byte* pBytes = bytes) fixed (char* pChars = &chars[0]) + fixed (byte* pBytes = bytes) fixed (char* pChars = &MemoryMarshal.GetReference((Span)chars)) // Remember that charCount is # to decode, not size of array return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null); }