diff --git a/src/Build/Evaluation/IntrinsicFunctions.cs b/src/Build/Evaluation/IntrinsicFunctions.cs
index 3fff5c28e65..3b60f4f1a4c 100644
--- a/src/Build/Evaluation/IntrinsicFunctions.cs
+++ b/src/Build/Evaluation/IntrinsicFunctions.cs
@@ -398,11 +398,11 @@ internal static string ConvertFromBase64(string toDecode)
}
///
- /// Hash the string independent of bitness and target framework.
+ /// Hash the string independent of bitness, target framework and default codepage of the environment.
///
internal static int StableStringHash(string toHash)
{
- return CommunicationsUtilities.GetHashCode(toHash);
+ return FowlerNollVo1aHash.ComputeHash32(toHash);
}
///
diff --git a/src/Build/Logging/BinaryLogger/BuildEventArgsWriter.cs b/src/Build/Logging/BinaryLogger/BuildEventArgsWriter.cs
index 0a21182e83c..ffc7d17dbc0 100644
--- a/src/Build/Logging/BinaryLogger/BuildEventArgsWriter.cs
+++ b/src/Build/Logging/BinaryLogger/BuildEventArgsWriter.cs
@@ -14,6 +14,7 @@
using Microsoft.Build.Framework;
using Microsoft.Build.Framework.Profiler;
using Microsoft.Build.Shared;
+using Microsoft.Build.Utilities;
#nullable disable
@@ -1274,13 +1275,13 @@ public HashKey(string text)
}
else
{
- value = FnvHash64.GetHashCode(text);
+ value = FowlerNollVo1aHash.ComputeHash64Fast(text);
}
}
public static HashKey Combine(HashKey left, HashKey right)
{
- return new HashKey(FnvHash64.Combine(left.value, right.value));
+ return new HashKey(FowlerNollVo1aHash.Combine64(left.value, right.value));
}
public HashKey Add(HashKey other) => Combine(this, other);
@@ -1310,35 +1311,5 @@ public override string ToString()
return value.ToString();
}
}
-
- internal static class FnvHash64
- {
- public const ulong Offset = 14695981039346656037;
- public const ulong Prime = 1099511628211;
-
- public static ulong GetHashCode(string text)
- {
- ulong hash = Offset;
-
- unchecked
- {
- for (int i = 0; i < text.Length; i++)
- {
- char ch = text[i];
- hash = (hash ^ ch) * Prime;
- }
- }
-
- return hash;
- }
-
- public static ulong Combine(ulong left, ulong right)
- {
- unchecked
- {
- return (left ^ right) * Prime;
- }
- }
- }
}
}
diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj
index a42e76cc270..67490385761 100644
--- a/src/Build/Microsoft.Build.csproj
+++ b/src/Build/Microsoft.Build.csproj
@@ -153,6 +153,7 @@
+
diff --git a/src/Build/Utilities/FowlerNollVo1aHash.cs b/src/Build/Utilities/FowlerNollVo1aHash.cs
new file mode 100644
index 00000000000..a9b319e7cc0
--- /dev/null
+++ b/src/Build/Utilities/FowlerNollVo1aHash.cs
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.Build.Utilities
+{
+ internal static class FowlerNollVo1aHash
+ {
+ // Fowler/Noll/Vo hashing.
+ // http://www.isthe.com/chongo/tech/comp/fnv/
+ // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash
+ // http://www.isthe.com/chongo/src/fnv/hash_32a.c
+
+ // 32 bit FNV prime and offset basis for FNV-1a.
+ private const uint fnvPrimeA32Bit = 16777619;
+ private const uint fnvOffsetBasisA32Bit = 2166136261;
+
+ // 64 bit FNV prime and offset basis for FNV-1a.
+ private const ulong fnvPrimeA64Bit = 1099511628211;
+ private const ulong fnvOffsetBasisA64Bit = 14695981039346656037;
+
+ ///
+ /// Computes 32 bit Fowler/Noll/Vo-1a hash of a string (regardless of encoding).
+ ///
+ /// String to be hashed.
+ /// 32 bit signed hash
+ internal static int ComputeHash32(string text)
+ {
+ uint hash = fnvOffsetBasisA32Bit;
+
+ unchecked
+ {
+ for (int i = 0; i < text.Length; i++)
+ {
+ char ch = text[i];
+ byte b = (byte)ch;
+ hash ^= b;
+ hash *= fnvPrimeA32Bit;
+
+ b = (byte)(ch >> 8);
+ hash ^= b;
+ hash *= fnvPrimeA32Bit;
+ }
+ }
+
+ return unchecked((int)hash);
+ }
+
+ ///
+ /// Computes 64 bit Fowler/Noll/Vo-1a hash optimized for ASCII strings.
+ /// The hashing algorithm considers only the first 8 bits of each character.
+ /// Analysis: https://github.com/KirillOsenkov/MSBuildStructuredLog/wiki/String-Hashing#faster-fnv-1a
+ ///
+ /// String to be hashed.
+ /// 64 bit unsigned hash
+ internal static ulong ComputeHash64Fast(string text)
+ {
+ ulong hash = fnvOffsetBasisA64Bit;
+
+ unchecked
+ {
+ for (int i = 0; i < text.Length; i++)
+ {
+ char ch = text[i];
+
+ hash = (hash ^ ch) * fnvPrimeA64Bit;
+ }
+ }
+
+ return hash;
+ }
+
+ ///
+ /// Computes 64 bit Fowler/Noll/Vo-1a hash of a string (regardless of encoding).
+ ///
+ /// String to be hashed.
+ /// 64 bit unsigned hash
+ internal static ulong ComputeHash64(string text)
+ {
+ ulong hash = fnvOffsetBasisA64Bit;
+
+ unchecked
+ {
+ for (int i = 0; i < text.Length; i++)
+ {
+ char ch = text[i];
+ byte b = (byte)ch;
+ hash ^= b;
+ hash *= fnvPrimeA64Bit;
+
+ b = (byte)(ch >> 8);
+ hash ^= b;
+ hash *= fnvPrimeA64Bit;
+ }
+ }
+
+ return hash;
+ }
+
+ internal static ulong Combine64(ulong left, ulong right)
+ {
+ unchecked
+ {
+ return (left ^ right) * fnvPrimeA64Bit;
+ }
+ }
+ }
+}
diff --git a/src/Tasks/Microsoft.Common.CurrentVersion.targets b/src/Tasks/Microsoft.Common.CurrentVersion.targets
index 316a44681b9..4c1a4b8f53b 100644
--- a/src/Tasks/Microsoft.Common.CurrentVersion.targets
+++ b/src/Tasks/Microsoft.Common.CurrentVersion.targets
@@ -385,11 +385,19 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<_GenerateBindingRedirectsIntermediateAppConfig>$(IntermediateOutputPath)$(TargetFileName).config
+
+
+ $(MSBuildProjectFile)
+
+ $(MSBuildProjectFile.Substring(0,8)).$(ProjectGuid.Substring(1,8))
+
+ $(MSBuildProjectFile.Substring(0,8)).$([MSBuild]::StableStringHash($(MSBuildProjectFile)).ToString("X8"))
+
-
+