Index: mcs/class/corlib/System/String.cs
===================================================================
--- mcs/class/corlib/System/String.cs	(revision 58086)
+++ mcs/class/corlib/System/String.cs	(working copy)
@@ -1837,7 +1837,7 @@
 			}
 		}
 
-		internal static unsafe void memcpy4 (byte *dest, byte *src, int size) {
+		static unsafe void memcpy4 (byte *dest, byte *src, int size) {
 			/*while (size >= 32) {
 				// using long is better than int and slower than double
 				// FIXME: enable this only on correct alignment or on platforms
@@ -1915,7 +1915,8 @@
 			if (size > 0)
 				((byte*)dest) [0] = ((byte*)src) [0];
 		}
-		static unsafe void memcpy (byte *dest, byte *src, int size) {
+
+		internal static unsafe void memcpy (byte *dest, byte *src, int size) {
 			// FIXME: if pointers are not aligned, try to align them
 			// so a faster routine can be used. Handle the case where
 			// the pointers can't be reduced to have the same alignment
Index: mcs/class/corlib/System.Text/UnicodeEncoding.cs
===================================================================
--- mcs/class/corlib/System.Text/UnicodeEncoding.cs	(revision 58086)
+++ mcs/class/corlib/System.Text/UnicodeEncoding.cs	(working copy)
@@ -92,7 +92,6 @@
 		return count * 2;
 	}
 
-	// Convenience wrappers for "GetByteCount".
 	public override int GetByteCount (String s)
 	{
 		if (s == null) {
@@ -101,9 +100,23 @@
 		return s.Length * 2;
 	}
 
+#if NET_2_0
+	[CLSCompliantAttribute(false)]
+	public unsafe override int GetByteCount (char* chars, int count)
+	{
+		if (chars == null) {
+			throw new ArgumentNullException ("chars");
+		}
+		if (count < 0) {
+			throw new ArgumentOutOfRangeException ("count");
+		}
+		return count * 2;
+	}
+#endif
+
 	// Get the bytes that result from encoding a character buffer.
-	public override int GetBytes (char[] chars, int charIndex, int charCount,
-								 byte[] bytes, int byteIndex)
+	public unsafe override int GetBytes (char[] chars, int charIndex, int charCount,
+										byte[] bytes, int byteIndex)
 	{
 		if (chars == null) {
 			throw new ArgumentNullException ("chars");
@@ -120,30 +133,29 @@
 		if (byteIndex < 0 || byteIndex > bytes.Length) {
 			throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
 		}
-		if ((bytes.Length - byteIndex) < (charCount * 2)) {
-			throw new ArgumentException (_("Arg_InsufficientSpace"));
+
+		fixed (char* charPtr = chars)
+			fixed (byte* bytePtr = bytes)
+				return GetBytesInternal (charPtr + charIndex, charCount, bytePtr + byteIndex, bytes.Length - byteIndex);
+	}
+
+#if !NET_2_0
+	public unsafe override byte[] GetBytes (String s)
+	{
+		if (s == null) {
+			throw new ArgumentNullException ("s");
 		}
-		int posn = byteIndex;
-		char ch;
-		if (bigEndian) {
-			while (charCount-- > 0) {
-				ch = chars[charIndex++];
-				bytes[posn++] = (byte)(ch >> 8);
-				bytes[posn++] = (byte)ch;
-			}
-		} else {
-			while (charCount-- > 0) {
-				ch = chars[charIndex++];
-				bytes[posn++] = (byte)ch;
-				bytes[posn++] = (byte)(ch >> 8);
-			}
-		}
-		return posn - byteIndex;
+		int byteCount = GetByteCount (s);
+		byte[] bytes = new byte[byteCount];
+		fixed (char* charPtr = s)
+			fixed (byte* bytePtr = bytes)
+				GetBytesInternal (charPtr, s.Length, bytePtr, byteCount);
+		return bytes;
 	}
+#endif
 
-	// Convenience wrappers for "GetBytes".
-	public override int GetBytes (String s, int charIndex, int charCount,
-								 byte[] bytes, int byteIndex)
+	public unsafe override int GetBytes (String s, int charIndex, int charCount,
+										byte[] bytes, int byteIndex)
 	{
 		if (s == null) {
 			throw new ArgumentNullException ("s");
@@ -160,27 +172,44 @@
 		if (byteIndex < 0 || byteIndex > bytes.Length) {
 			throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
 		}
-		if ((bytes.Length - byteIndex) < (charCount * 2)) {
-			throw new ArgumentException (_("Arg_InsufficientSpace"));
+		fixed (char* charPtr = s)
+			fixed (byte* bytePtr = bytes)
+				return GetBytesInternal (charPtr + charIndex, charCount, bytePtr + byteIndex, bytes.Length - byteIndex);
+	}
+
+#if NET_2_0
+	[CLSCompliantAttribute(false)]
+	public unsafe override int GetBytes (char *chars, int charCount,
+										byte *bytes, int byteCount)
+	{
+		if (bytes == null) {
+			throw new ArgumentNullException ("bytes");
 		}
-		int posn = byteIndex;
-		char ch;
-		if (bigEndian) {
-			while (charCount-- > 0) {
-				ch = s[charIndex++];
-				bytes[posn++] = (byte)(ch >> 8);
-				bytes[posn++] = (byte)ch;
-			}
-		} else {
-			while (charCount-- > 0) {
-				ch = s[charIndex++];
-				bytes[posn++] = (byte)ch;
-				bytes[posn++] = (byte)(ch >> 8);
-			}
+		if (chars == null) {
+			throw new ArgumentNullException ("chars");
 		}
-		return posn - byteIndex;
+		if (charCount < 0) {
+			throw new ArgumentOutOfRangeException ("charCount");
+		}
+		if (byteCount < 0) {
+			throw new ArgumentOutOfRangeException ("byteCount");
+		}
+		return GetBytesInternal (chars, charCount, bytes, byteCount);
 	}
+#endif
 
+	private unsafe int GetBytesInternal (char* chars, int charCount,
+										byte* bytes, int byteCount)
+	{
+		int count = charCount * 2;
+
+		if (byteCount < count) {
+			throw new ArgumentException (_("Arg_InsufficientSpace"));
+		}
+		CopyChars ((byte*)chars, bytes, count, bigEndian);
+		return count;
+	}
+
 	// Get the number of characters needed to decode a byte buffer.
 	public override int GetCharCount (byte[] bytes, int index, int count)
 	{
@@ -196,8 +225,22 @@
 		return count / 2;
 	}
 
+#if NET_2_0
+	[CLSCompliantAttribute(false)]
+	public unsafe override int GetCharCount (byte* bytes, int count)
+	{
+		if (bytes == null) {
+			throw new ArgumentNullException ("bytes");
+		}
+		if (count < 0) {
+			throw new ArgumentOutOfRangeException ("count");
+		}
+		return count / 2;
+	}
+#endif
+
 	// Get the characters that result from decoding a byte buffer.
-	public override int GetChars (byte[] bytes, int byteIndex, int byteCount,
+	public unsafe override int GetChars (byte[] bytes, int byteIndex, int byteCount,
 								 char[] chars, int charIndex)
 	{
 		if (bytes == null) {
@@ -215,13 +258,44 @@
 		if (charIndex < 0 || charIndex > chars.Length) {
 			throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
 		}
+		fixed (byte* bytePtr = bytes)
+			fixed (char* charPtr = chars)
+				return GetCharsInternal (bytePtr + byteIndex, byteCount, charPtr + charIndex, chars.Length - charIndex);
+	}
 
+#if NET_2_0
+		[CLSCompliantAttribute(false)]
+		public unsafe override int GetChars (byte* bytes, int byteCount,
+											char* chars, int charCount)
+		{
+			if (bytes == null) {
+				throw new ArgumentNullException ("bytes");
+			}
+			if (chars == null) {
+				throw new ArgumentNullException ("chars");
+			}
+			if (charCount < 0) {
+				throw new ArgumentOutOfRangeException ("charCount");
+			}
+			if (byteCount < 0) {
+				throw new ArgumentOutOfRangeException ("byteCount");
+			}
+			return GetCharsInternal (bytes, byteCount, chars, charCount);
+		}
+#endif
+
+	private unsafe int GetCharsInternal (byte* bytes, int byteCount,
+										char* chars, int charCount)
+	{
+		int count = byteCount / 2;
+		bool isBigEndian;
+
 		// Determine the byte order in the incoming buffer.
-		bool isBigEndian;
-		if (byteCount >= 2) {
-			if (bytes[byteIndex] == (byte)0xFE && bytes[byteIndex + 1] == (byte)0xFF) {
+		if (byteCount >= 2) 
+		{
+			if (bytes[0] == (byte)0xFE && bytes[1] == (byte)0xFF) {
 				isBigEndian = true;
-			} else if (bytes[byteIndex] == (byte)0xFF && bytes[byteIndex + 1] == (byte)0xFE) {
+			} else if (bytes[0] == (byte)0xFF && bytes[1] == (byte)0xFE) {
 				isBigEndian = false;
 			} else {
 				isBigEndian = bigEndian;
@@ -231,30 +305,12 @@
 		}
 
 		// Validate that we have sufficient space in "chars".
-		if ((chars.Length - charIndex) < (byteCount / 2)) {
+		if (charCount < count) {
 			throw new ArgumentException (_("Arg_InsufficientSpace"));
 		}
 
-		// Convert the characters.
-		int posn = charIndex;
-		if (isBigEndian) {
-			while (byteCount >= 2) {
-				chars[posn++] =
-					((char)((((int)(bytes[byteIndex])) << 8) |
-							 ((int)(bytes[byteIndex + 1]))));
-				byteIndex += 2;
-				byteCount -= 2;
-			}
-		} else {
-			while (byteCount >= 2) {
-				chars[posn++] =
-					((char)((((int)(bytes[byteIndex + 1])) << 8) |
-							 ((int)(bytes[byteIndex]))));
-				byteIndex += 2;
-				byteCount -= 2;
-			}
-		}
-		return posn - charIndex;
+		CopyChars ((byte*)chars, bytes, byteCount & unchecked((int)0xFFFFFFFE), isBigEndian);
+		return count;
 	}
 
 	// Get the maximum number of bytes needed to encode a
@@ -321,6 +377,119 @@
 		return base.GetHashCode ();
 	}
 
+	private unsafe static void CopyChars (byte* src, byte* dest, int count, bool bigEndian)
+	{
+		if (BitConverter.IsLittleEndian != bigEndian)
+			string.memcpy (dest, src, count);
+		else {
+			switch (count) {
+				case 0:
+					return;
+				case 1:
+					return;
+				case 2:
+					goto Count2;
+				case 3:
+					goto Count2;
+				case 4:
+					goto Count4;
+				case 5:
+					goto Count4;
+				case 6:
+					goto Count4;
+				case 7:
+					goto Count4;
+				case 8:
+					goto Count8;
+				case 9:
+					goto Count8;
+				case 10:
+					goto Count8;
+				case 11:
+					goto Count8;
+				case 12:
+					goto Count8;
+				case 13:
+					goto Count8;
+				case 14:
+					goto Count8;
+				case 15:
+					goto Count8;
+			}
+
+			do {
+				dest[0] = src[1];
+				dest[1] = src[0];
+				dest[2] = src[3];
+				dest[3] = src[2];
+				dest[4] = src[5];
+				dest[5] = src[4];
+				dest[6] = src[7];
+				dest[7] = src[6];
+				dest[8] = src[9];
+				dest[9] = src[8];
+				dest[10] = src[11];
+				dest[11] = src[10];
+				dest[12] = src[13];
+				dest[13] = src[12];
+				dest[14] = src[15];
+				dest[15] = src[14];
+				dest += 16;
+				src += 16;
+				count -= 16;
+			} while ((count & unchecked((int)0xFFFFFFF0)) != 0);
+
+			switch (count) 
+			{
+				case 0:
+					return;
+				case 1:
+					return;
+				case 2:
+					goto Count2;
+				case 3:
+					goto Count2;
+				case 4:
+					goto Count4;
+				case 5:
+					goto Count4;
+				case 6:
+					goto Count4;
+				case 7:
+					goto Count4;
+			}
+
+			Count8:;
+			dest[0] = src[1];
+			dest[1] = src[0];
+			dest[2] = src[3];
+			dest[3] = src[2];
+			dest[4] = src[5];
+			dest[5] = src[4];
+			dest[6] = src[7];
+			dest[7] = src[6];
+			dest += 8;
+			src += 8;
+
+			if ((count & 4) == 0)
+				goto TestCount2;
+			Count4:;
+			dest[0] = src[1];
+			dest[1] = src[0];
+			dest[2] = src[3];
+			dest[3] = src[2];
+			dest += 4;
+			src += 4;
+
+			TestCount2:;
+			if ((count & 2) == 0)
+				return;
+			Count2:;
+			dest[0] = src[1];
+			dest[1] = src[0];
+		}
+	}
+
 	// Unicode decoder implementation.
 	private sealed class UnicodeDecoder : Decoder
 	{
@@ -419,20 +588,6 @@
 		}
 
 	} // class UnicodeDecoder
-	
-#if NET_2_0
-	[CLSCompliantAttribute(false)]
-	public unsafe override int GetByteCount (char *chars, int count)
-	{
-		return count * 2;
-	}
-#else
-	public override byte [] GetBytes (String s)
-	{
-		return base.GetBytes (s);
-	}
-#endif
-	
 
 }; // class UnicodeEncoding
 
