diff --git a/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj b/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj
index 5ec78a92068..18ad711bac4 100644
--- a/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj
+++ b/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj
@@ -99,10 +99,6 @@
True
-
-
-
-
true
diff --git a/src/Build.UnitTests/OpportunisticIntern_Tests.cs b/src/Build.UnitTests/OpportunisticIntern_Tests.cs
deleted file mode 100644
index c47f751c349..00000000000
--- a/src/Build.UnitTests/OpportunisticIntern_Tests.cs
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System;
-using System.Text;
-using Microsoft.Build.Shared;
-using Xunit;
-using Xunit.Abstractions;
-
-namespace Microsoft.Build.UnitTests
-{
- public abstract class OpportunisticInternTestBase : IDisposable
- {
- protected TestEnvironment _env;
-
- public void Dispose()
- {
- _env.Dispose();
- }
-
- protected OpportunisticInternTestBase(ITestOutputHelper testOutput)
- {
- _env = TestEnvironment.Create(testOutput);
- }
-
- private static bool IsInternable(IInternable internable)
- {
- string i1 = OpportunisticIntern.InternableToString(internable);
- string i2 = OpportunisticIntern.InternableToString(internable);
- Assert.Equal(i1, i2); // No matter what, the same string value should return.
- return Object.ReferenceEquals(i1, i2);
- }
-
- private static void AssertInternable(IInternable internable)
- {
- Assert.True(IsInternable(internable));
- }
-
- private static void AssertInternable(StringBuilder sb)
- {
- AssertInternable(new StringBuilderInternTarget(sb));
- }
-
- private static string AssertInternable(char[] ch, int startIndex, int count)
- {
- var target = new CharArrayInternTarget(ch, startIndex, count);
- AssertInternable(target);
- Assert.Equal(target.Length, count);
-
- return target.ExpensiveConvertToString();
- }
-
- private static void AssertInternable(string value)
- {
- AssertInternable(new StringBuilder(value));
- AssertInternable(value.ToCharArray(), 0, value.ToCharArray().Length);
- }
-
- private static void AssertNotInternable(IInternable internable)
- {
- Assert.False(IsInternable(internable));
- }
-
- private static void AssertNotInternable(StringBuilder sb)
- {
- AssertNotInternable(new StringBuilderInternTarget(sb));
- }
-
- private static void AssertNotInternable(char[] ch)
- {
- AssertNotInternable(new CharArrayInternTarget(ch, ch.Length));
- }
-
- protected static void AssertNotInternable(string value)
- {
- AssertNotInternable(new StringBuilder(value));
- AssertNotInternable(value.ToCharArray());
- }
-
- ///
- /// Test interning segment of char array
- ///
- [Fact]
- public void SubArray()
- {
- var result = AssertInternable(new char[] { 'a', 't', 'r', 'u', 'e' }, 1, 4);
-
- Assert.Equal("true", result);
- }
-
- ///
- /// Test interning segment of char array
- ///
- [Fact]
- public void SubArray2()
- {
- var result = AssertInternable(new char[] { 'a', 't', 'r', 'u', 'e', 'x' }, 1, 4);
-
- Assert.Equal("true", result);
- }
-
- ///
- /// Unique strings should not be interned
- ///
- [Fact]
- public void NonInternableDummyGlobalVariable()
- {
- AssertNotInternable($"{MSBuildConstants.MSBuildDummyGlobalPropertyHeader}{new string('1', 100)}");
- }
-
- ///
- /// This is the list of hard-coded interns. They should report interned even though they are too small for normal interning.
- ///
- [Fact]
- public void KnownInternableTinyStrings()
- {
- AssertInternable("C#");
- AssertInternable("F#");
- AssertInternable("VB");
- AssertInternable("True");
- AssertInternable("TRUE");
- AssertInternable("Copy");
- AssertInternable("v4.0");
- AssertInternable("true");
- AssertInternable("FALSE");
- AssertInternable("false");
- AssertInternable("Debug");
- AssertInternable("Build");
- AssertInternable("''!=''");
- AssertInternable("AnyCPU");
- AssertInternable("Library");
- AssertInternable("MSBuild");
- AssertInternable("Release");
- AssertInternable("ResolveAssemblyReference");
- }
-
- ///
- /// Test a set of strings that are similar to each other
- ///
- [Fact]
- public void InternableDifferingOnlyByNthCharacter()
- {
- string test = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890!@#$%^&*()_+ABCDEFGHIJKLMNOPQRSTUVabcdefghijklmnopqrstuvwxyz0150";
- for (int i = 0; i < test.Length; ++i)
- {
- string mutated = test.Substring(0, i) + " " + test.Substring(i + 1);
- AssertInternable(mutated);
- }
- }
-
- ///
- /// Test The empty string
- ///
- [Fact]
- public void StringDotEmpty()
- {
- AssertInternable(String.Empty);
- }
-
- ///
- /// Test an empty string.
- ///
- [Fact]
- public void DoubleDoubleQuotes()
- {
- AssertInternable("");
- }
- }
-
- ///
- /// Tests the new (default) implementation of OpportunisticIntern.
- ///
- public class OpportunisticIntern_Tests : OpportunisticInternTestBase
- {
- public OpportunisticIntern_Tests(ITestOutputHelper testOutput)
- : base(testOutput)
- {
- OpportunisticIntern.ResetForTests();
- }
- }
-
- ///
- /// Tests the legacy implementation of OpportunisticIntern.
- ///
- public class OpportunisticInternLegacy_Tests : OpportunisticInternTestBase
- {
- public OpportunisticInternLegacy_Tests(ITestOutputHelper testOutput)
- : base(testOutput)
- {
- _env.SetEnvironmentVariable("MSBuildUseLegacyStringInterner", "1");
- OpportunisticIntern.ResetForTests();
- }
-
- ///
- /// The legacy implementation does not intern tiny strings unless they are on the hard-coded list.
- ///
- [Fact]
- public void NonInternableTinyString()
- {
- AssertNotInternable("1234");
- }
- }
-
- ///
- /// Tests the legacy implementation of OpportunisticIntern with simple concurrency enabled.
- ///
- public class OpportunisticInternLegacySimpleConcurrecy_Tests : OpportunisticInternTestBase
- {
- public OpportunisticInternLegacySimpleConcurrecy_Tests(ITestOutputHelper testOutput)
- : base(testOutput)
- {
- _env.SetEnvironmentVariable("MSBuildUseLegacyStringInterner", "1");
- _env.SetEnvironmentVariable("MSBuildUseSimpleInternConcurrency", "1");
- OpportunisticIntern.ResetForTests();
- }
- }
-}
diff --git a/src/Build.UnitTests/WeakStringCache_Tests.cs b/src/Build.UnitTests/WeakStringCache_Tests.cs
deleted file mode 100644
index ece79899fd0..00000000000
--- a/src/Build.UnitTests/WeakStringCache_Tests.cs
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-
-using Shouldly;
-using Xunit;
-
-namespace Microsoft.Build.UnitTests
-{
- public class WeakStringCache_Tests : IDisposable
- {
- ///
- /// The weak string cache under test.
- ///
- private WeakStringCache _cache = new WeakStringCache();
-
- public void Dispose()
- {
- _cache.Dispose();
- }
-
- ///
- /// Adds a string to the cache under test.
- ///
- /// Part one of the string (split to prevent runtime interning and unintended GC roots).
- /// Part two of the string (split to prevent runtime interning and unintended GC roots).
- /// Callback to be invoked after the string has been added but before the strong GC ref is released.
- /// The hash code of the string as calculated by WeakStringCache.
- [MethodImpl(MethodImplOptions.NoInlining)]
- private int AddString(string strPart1, string strPart2, Action callbackToRunWithTheStringAlive)
- {
- // Compose the string with SB so it doesn't get interned by the runtime.
- string testString = new StringBuilder(strPart1).Append(strPart2).ToString();
- StringInternTarget testStringTarget = new StringInternTarget(testString);
-
- int hashCode = WeakStringCache.GetInternableHashCode(testStringTarget);
-
- string cachedString = _cache.GetOrCreateEntry(testStringTarget, out bool cacheHit);
- cacheHit.ShouldBeFalse();
- cachedString.ShouldBeSameAs(testString);
-
- callbackToRunWithTheStringAlive(cachedString);
-
- // Verify that the string is really in the cache and the cache returns the interned instance.
- string testStringCopy = new StringBuilder(strPart1).Append(strPart2).ToString();
- cachedString = _cache.GetOrCreateEntry(new StringInternTarget(testStringCopy), out cacheHit);
- cacheHit.ShouldBeTrue();
- cachedString.ShouldBeSameAs(testString);
-
- // Trigger full GC and verify that nothing has changed since we're still keeping testString alive.
- GC.Collect();
-
- callbackToRunWithTheStringAlive(cachedString);
-
- cachedString = _cache.GetOrCreateEntry(new StringInternTarget(testStringCopy), out cacheHit);
- cacheHit.ShouldBeTrue();
- cachedString.ShouldBeSameAs(testString);
-
- return hashCode;
- }
-
- ///
- /// Adds strings that are known to have a hash code collision to the cache under test.
- ///
- [MethodImpl(MethodImplOptions.NoInlining)]
- private void AddStringsWithSameHashCode(int numberOfStrings)
- {
- string[] cachedStrings = new string[numberOfStrings];
- int[] hashCodes = new int[numberOfStrings];
-
- for (int i = 0; i < numberOfStrings; i++)
- {
- string strPart2 = "1" + String.Concat(Enumerable.Repeat("4428939786", i));
- hashCodes[i] = AddString("Random string ", strPart2, (string cachedString) =>
- {
- _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo()
- {
- LiveStringCount = 1,
- CollectedStringCount = 0,
- });
- cachedStrings[i] = cachedString;
- });
-
- if (i > 0)
- {
- // The strings have been carefully constructed to have the same hash code.
- hashCodes[i].ShouldBe(hashCodes[i - 1]);
- }
- }
-
- // There are no cache hits when iterating over our strings again because the last one always wins and steals the slot.
- for (int i = 0; i < numberOfStrings; i++)
- {
- StringBuilder sb = new StringBuilder(cachedStrings[i]);
- string cachedStringFromCache =_cache.GetOrCreateEntry(new StringBuilderInternTarget(sb), out bool cacheHit);
- cacheHit.ShouldBeFalse();
- cachedStringFromCache.ShouldNotBeSameAs(cachedStrings[i]);
- }
- }
-
- ///
- /// Simple test case to verify that:
- /// 1. A string added to the cache stays in the cache as long as it's alive.
- /// 2. The string is no longer retrievable after all strong GC refs are gone.
- /// 3. The cache completely removes the handle after calling Scavenge on it.
- ///
- ///
- /// Disabled on MacOS Mono because it doesn't play well with conservative GC scanning.
- /// https://www.mono-project.com/docs/advanced/garbage-collector/sgen/#precise-stack-marking
- ///
- [Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.Mono, "doesn't play well with conservative GC scanning")]
- public void RetainsStringUntilCollected()
- {
- // Add a string to the cache using a non-inlinable method to make sure it's not reachable from a GC root.
- AddString("Random string ", "test", (string cachedString) =>
- {
- _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo()
- {
- LiveStringCount = 1,
- CollectedStringCount = 0,
- });
- });
-
- // Trigger full GC.
- GC.Collect();
-
- // The handle is still in the cache but it's unused now as the string has been collected.
- _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo()
- {
- LiveStringCount = 0,
- CollectedStringCount = 1,
- });
-
- // Ask the cache to get rid of unused handles.
- _cache.Scavenge();
-
- // The cache should be empty now.
- _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo()
- {
- LiveStringCount = 0,
- CollectedStringCount = 0,
- });
- }
-
- ///
- /// Same as RetainsStringUntilCollected but with multiple strings sharing the same hash code.
- ///
- ///
- /// Disabled on MacOS Mono because it doesn't play well with conservative GC scanning.
- /// https://www.mono-project.com/docs/advanced/garbage-collector/sgen/#precise-stack-marking
- ///
- [Fact]
- [Trait("Category", "mono-osx-failing")]
- public void RetainsLastStringWithGivenHashCode()
- {
- // Add 3 strings with the same hash code.
- AddStringsWithSameHashCode(3);
-
- // Trigger full GC.
- GC.Collect();
-
- // The handle is still in the cache but it's unused now as the strings have been collected.
- _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo()
- {
- LiveStringCount = 0,
- CollectedStringCount = 1,
- });
-
- // Ask the cache to get rid of unused handles.
- _cache.Scavenge();
-
- // The cache should be empty now.
- _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo()
- {
- LiveStringCount = 0,
- CollectedStringCount = 0,
- });
- }
- }
-}
diff --git a/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj b/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj
index 83bcbfcf5c0..b73c360d59d 100644
--- a/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj
+++ b/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj
@@ -44,10 +44,6 @@
-
-
-
-
diff --git a/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj b/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj
index 30db3703d9b..209e21d4d1e 100644
--- a/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj
+++ b/src/UnitTests.Shared/Microsoft.Build.UnitTests.Shared.csproj
@@ -63,18 +63,6 @@
NativeMethodsShared.cs
-
- IInternable.cs
-
-
- WeakStringCache.cs
-
-
- WeakStringCache.Concurrent.cs
-
-
- OpportunisticIntern.cs
-
ResourceUtilities.cs