Skip to content

Staged changes: Hashing improvements #20204

Description

@xperiandri

The following staged changes are ready for review:

--- a/src/Compiler/Facilities/Hashing.fs
+++ b/src/Compiler/Facilities/Hashing.fs
@@ -1,6 +1,7 @@
 namespace Internal.Utilities.Hashing
 
 open System
+open System.Security.Cryptography
 open System.Threading
@@ -43,19 +44,50 @@ module internal Md5StringHasher =
 
 module internal Md5Hasher =
 
+#if NETSTANDARD2_0
     let private md5 =
-        new ThreadLocal<_>(fun () -> System.Security.Cryptography.MD5.Create())
+        new ThreadLocal<_>(fun () -> MD5.Create())
 
-    let computeHash (bytes: byte array) =
-        // md5.Value.ComputeHash(bytes) TODO: the threadlocal is not working in new VS extension
-        ignore md5
-        let md5 = System.Security.Cryptography.MD5.Create()
-        md5.ComputeHash(bytes)
+    let computeHash (bytes: byte array) = md5.Value.ComputeHash(bytes)
+#else
+    let computeHash (bytes: byte array) = MD5.HashData(bytes)
+#endif
@@
     let empty = Array.empty
@@
+    /// Computes the MD5 hash of a string directly into a caller-allocated 16-byte buffer,
+    /// avoiding the extra allocation of an intermediate hash-result array.
+    /// The UTF8 encoding buffer is rented from the shared ArrayPool to avoid allocating
+    /// a byte array the size of the input string on every call.
+    let hashStringInto (s: string) (destination: Span<byte>) =
+        let encoding = System.Text.Encoding.UTF8
+        let maxByteCount = encoding.GetMaxByteCount(s.Length)
+        let rented = System.Buffers.ArrayPool<byte>.Shared.Rent(maxByteCount)
+
+        try
+            let byteCount = encoding.GetBytes(s, 0, s.Length, rented, 0)
+#if NETSTANDARD2_0
+            let hash = md5.Value.ComputeHash(rented, 0, byteCount)
+            hash.CopyTo(destination)
+#else
+            let mutable bytesWritten = 0
+            MD5.TryHashData(ReadOnlySpan(rented, 0, byteCount), destination, &bytesWritten) |> ignore
+#endif
+        finally
+            System.Buffers.ArrayPool<byte>.Shared.Return(rented)
@@
-    let hashString (s: string) =
-        s |> System.Text.Encoding.UTF8.GetBytes |> computeHash
+    let hashString (s: string) =
+        let bytes = Array.zeroCreate<byte> 16
+        hashStringInto s (Span bytes)
+        bytes
@@
-    let hashStringToString (s: string) =
-        s |> System.Text.Encoding.UTF8.GetBytes |> computeHash
+    let hashStringToString (s: string) =
+        let bytes = Array.zeroCreate<byte> 16
+        hashStringInto s (Span bytes)
+        BitConverter.ToString(bytes)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status
    New

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions