Reduced code size and optimized name key creation for JSON properties and parameters...
authorYoh Deadfall <yoh.deadfall@hotmail.com>
Fri, 7 Aug 2020 22:18:28 +0000 (01:18 +0300)
committerGitHub <noreply@github.com>
Fri, 7 Aug 2020 22:18:28 +0000 (17:18 -0500)
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs

index 7b01b16..0de7ed3 100644 (file)
@@ -446,84 +446,47 @@ namespace System.Text.Json
         /// </summary>
         // AggressiveInlining used since this method is only called from two locations and is on a hot path.
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static ulong GetKey(ReadOnlySpan<byte> propertyName)
+        public static ulong GetKey(ReadOnlySpan<byte> name)
         {
-            const int BitsInByte = 8;
             ulong key;
-            int length = propertyName.Length;
+
+            ref byte reference = ref MemoryMarshal.GetReference(name);
+            int length = name.Length;
 
             if (length > 7)
             {
-                key = MemoryMarshal.Read<ulong>(propertyName)
-                    & 0x00FFFFFFFFFFFFFF
-                    // Include the length with a max of 0xFF.
-                    | ((ulong)Math.Min(length, 0xFF)) << (7 * BitsInByte);
-            }
-            else if (length > 3)
-            {
-                key = MemoryMarshal.Read<uint>(propertyName);
-
-                if (length == 7)
-                {
-                    key |= (ulong)propertyName[6] << (6 * BitsInByte)
-                        | (ulong)propertyName[5] << (5 * BitsInByte)
-                        | (ulong)propertyName[4] << (4 * BitsInByte)
-                        | (ulong)7 << (7 * BitsInByte);
-                }
-                else if (length == 6)
-                {
-                    key |= (ulong)propertyName[5] << (5 * BitsInByte)
-                        | (ulong)propertyName[4] << (4 * BitsInByte)
-                        | (ulong)6 << (7 * BitsInByte);
-                }
-                else if (length == 5)
-                {
-                    key |= (ulong)propertyName[4] << (4 * BitsInByte)
-                        | (ulong)5 << (7 * BitsInByte);
-                }
-                else
-                {
-                    key |= (ulong)4 << (7 * BitsInByte);
-                }
+                key = Unsafe.ReadUnaligned<ulong>(ref reference) & 0x00ffffffffffffffL;
+                key |= (ulong)Math.Min(length, 0xff) << 56;
             }
-            else if (length > 1)
+            else
             {
-                key = MemoryMarshal.Read<ushort>(propertyName);
+                key =
+                    length > 5 ? Unsafe.ReadUnaligned<uint>(ref reference) | (ulong)Unsafe.ReadUnaligned<ushort>(ref Unsafe.Add(ref reference, 4)) << 32 :
+                    length > 3 ? Unsafe.ReadUnaligned<uint>(ref reference) :
+                    length > 1 ? Unsafe.ReadUnaligned<ushort>(ref reference) : 0UL;
+                key |= (ulong)length << 56;
 
-                if (length == 3)
-                {
-                    key |= (ulong)propertyName[2] << (2 * BitsInByte)
-                        | (ulong)3 << (7 * BitsInByte);
-                }
-                else
+                if ((length & 1) != 0)
                 {
-                    key |= (ulong)2 << (7 * BitsInByte);
+                    var offset = length - 1;
+                    key |= (ulong)Unsafe.Add(ref reference, offset) << (offset * 8);
                 }
             }
-            else if (length == 1)
-            {
-                key = propertyName[0]
-                    | (ulong)1 << (7 * BitsInByte);
-            }
-            else
-            {
-                // An empty name is valid.
-                key = 0;
-            }
 
             // Verify key contains the embedded bytes as expected.
+            const int BitsInByte = 8;
             Debug.Assert(
                 // Verify embedded property name.
-                (length < 1 || propertyName[0] == ((key & ((ulong)0xFF << BitsInByte * 0)) >> BitsInByte * 0)) &&
-                (length < 2 || propertyName[1] == ((key & ((ulong)0xFF << BitsInByte * 1)) >> BitsInByte * 1)) &&
-                (length < 3 || propertyName[2] == ((key & ((ulong)0xFF << BitsInByte * 2)) >> BitsInByte * 2)) &&
-                (length < 4 || propertyName[3] == ((key & ((ulong)0xFF << BitsInByte * 3)) >> BitsInByte * 3)) &&
-                (length < 5 || propertyName[4] == ((key & ((ulong)0xFF << BitsInByte * 4)) >> BitsInByte * 4)) &&
-                (length < 6 || propertyName[5] == ((key & ((ulong)0xFF << BitsInByte * 5)) >> BitsInByte * 5)) &&
-                (length < 7 || propertyName[6] == ((key & ((ulong)0xFF << BitsInByte * 6)) >> BitsInByte * 6)) &&
+                (name.Length < 1 || name[0] == ((key & ((ulong)0xFF << BitsInByte * 0)) >> BitsInByte * 0)) &&
+                (name.Length < 2 || name[1] == ((key & ((ulong)0xFF << BitsInByte * 1)) >> BitsInByte * 1)) &&
+                (name.Length < 3 || name[2] == ((key & ((ulong)0xFF << BitsInByte * 2)) >> BitsInByte * 2)) &&
+                (name.Length < 4 || name[3] == ((key & ((ulong)0xFF << BitsInByte * 3)) >> BitsInByte * 3)) &&
+                (name.Length < 5 || name[4] == ((key & ((ulong)0xFF << BitsInByte * 4)) >> BitsInByte * 4)) &&
+                (name.Length < 6 || name[5] == ((key & ((ulong)0xFF << BitsInByte * 5)) >> BitsInByte * 5)) &&
+                (name.Length < 7 || name[6] == ((key & ((ulong)0xFF << BitsInByte * 6)) >> BitsInByte * 6)) &&
                 // Verify embedded length.
-                (length >= 0xFF || (key & ((ulong)0xFF << BitsInByte * 7)) >> BitsInByte * 7 == (ulong)length) &&
-                (length < 0xFF || (key & ((ulong)0xFF << BitsInByte * 7)) >> BitsInByte * 7 == 0xFF));
+                (name.Length >= 0xFF || (key & ((ulong)0xFF << BitsInByte * 7)) >> BitsInByte * 7 == (ulong)name.Length) &&
+                (name.Length < 0xFF || (key & ((ulong)0xFF << BitsInByte * 7)) >> BitsInByte * 7 == 0xFF));
 
             return key;
         }