From: Marius Ungureanu Date: Fri, 2 Jun 2017 07:03:47 +0000 (-0700) Subject: [Posix] Optimize string marshal code by using unsafe code (#4964) X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=045232ef52603abcf570b771777489549301826b;p=mono.git [Posix] Optimize string marshal code by using unsafe code (#4964) --- diff --git a/mcs/class/Mono.Posix/Mono.Unix/UnixEncoding.cs b/mcs/class/Mono.Posix/Mono.Unix/UnixEncoding.cs index 1d8e40ca45c..d869b1b90c6 100644 --- a/mcs/class/Mono.Posix/Mono.Unix/UnixEncoding.cs +++ b/mcs/class/Mono.Posix/Mono.Unix/UnixEncoding.cs @@ -300,17 +300,35 @@ public class UnixEncoding : Encoding throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array")); } + unsafe { + fixed (char* p = s) { + fixed (byte* b = bytes) { + return GetBytes (p + charIndex, charCount, b + byteIndex, bytes.Length - byteIndex); + } + } + } + } + + public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount) + { + if (bytes == null || chars == null) + throw new ArgumentNullException (bytes == null ? "bytes" : "chars"); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException (charCount < 0 ? "charCount" : "byteCount"); + // Convert the characters into bytes. char ch; - int length = bytes.Length; + int length = byteCount; uint pair; - int posn = byteIndex; + int posn = 0; + int charIndex = 0; while (charCount > 0) { // Fetch the next UTF-16 character pair value. - ch = s[charIndex++]; + ch = chars [charIndex++]; if (ch >= '\uD800' && ch <= '\uDBFF' && charCount > 1) { // This may be the start of a surrogate pair. - pair = (uint)(s[charIndex]); + pair = (uint)(chars[charIndex]); if (pair >= (uint)0xDC00 && pair <= (uint)0xDFFF) { pair = (pair - (uint)0xDC00) + ((((uint)ch) - (uint)0xD800) << 10) + @@ -326,7 +344,7 @@ public class UnixEncoding : Encoding } charCount -= 2; if (charCount >= 0) { - bytes[posn++] = (byte) s [charIndex++]; + bytes[posn++] = (byte)chars [charIndex++]; } continue; } else { @@ -365,7 +383,7 @@ public class UnixEncoding : Encoding } // Return the final count to the caller. - return posn - byteIndex; + return posn; } // Internal version of "GetCharCount" which can handle a rolling @@ -394,7 +412,7 @@ public class UnixEncoding : Encoding uint leftSoFar = (leftOverCount & (uint)0x0F); uint leftSize = ((leftOverCount >> 4) & (uint)0x0F); while (count > 0) { - ch = (uint)(bytes[index++]); + ch = (uint)(bytes [index++]); ++next_raw; --count; if (leftSize == 0) { diff --git a/mcs/class/Mono.Posix/Mono.Unix/UnixMarshal.cs b/mcs/class/Mono.Posix/Mono.Unix/UnixMarshal.cs index 334b6f2a49b..0b01eb19ad4 100644 --- a/mcs/class/Mono.Posix/Mono.Unix/UnixMarshal.cs +++ b/mcs/class/Mono.Posix/Mono.Unix/UnixMarshal.cs @@ -325,27 +325,42 @@ namespace Mono.Unix { if (encoding == null) throw new ArgumentNullException ("encoding"); - int min_byte_count = encoding.GetMaxByteCount(1); - char[] copy = s.ToCharArray (index, count); - byte[] marshal = new byte [encoding.GetByteCount (copy) + min_byte_count]; + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException ((index < 0 ? "index" : "count"), + "Non - negative number required."); - int bytes_copied = encoding.GetBytes (copy, 0, copy.Length, marshal, 0); + if (s.Length - index < count) + throw new ArgumentOutOfRangeException ("s", "Index and count must refer to a location within the string."); - if (bytes_copied != (marshal.Length-min_byte_count)) - throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!"); + int null_terminator_count = encoding.GetMaxByteCount (1); + int length_without_null = encoding.GetByteCount (s); + int marshalLength = checked (length_without_null + null_terminator_count); - IntPtr mem = AllocHeap (marshal.Length); + IntPtr mem = AllocHeap (marshalLength); if (mem == IntPtr.Zero) throw new UnixIOException (Native.Errno.ENOMEM); - bool copied = false; - try { - Marshal.Copy (marshal, 0, mem, marshal.Length); - copied = true; - } - finally { - if (!copied) - FreeHeap (mem); + unsafe { + fixed (char* p = s) { + byte* marshal = (byte*)mem; + int bytes_copied; + + try { + bytes_copied = encoding.GetBytes (p + index, count, marshal, marshalLength); + } catch { + FreeHeap (mem); + throw; + } + + if (bytes_copied != length_without_null) { + FreeHeap (mem); + throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!"); + } + + marshal += length_without_null; + for (int i = 0; i < null_terminator_count; ++i) + marshal[i] = 0; + } } return mem;