Skip to content

Commit

Permalink
Merge pull request #1269 from ltrzesniewski/change-load-contexts
Browse files Browse the repository at this point in the history
Base load contexts on weaver paths
  • Loading branch information
tom-englert committed May 15, 2024
2 parents 4efd176 + 5057b82 commit c4a1446
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 13 deletions.
33 changes: 33 additions & 0 deletions Fody/AssemblyPathSet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Runtime.InteropServices;

namespace Fody;

public sealed class AssemblyPathSet : IEquatable<AssemblyPathSet>
{
readonly HashSet<string> assemblyPaths;
readonly int hashCode;

public IReadOnlyCollection<string> AssemblyPaths => assemblyPaths;

public AssemblyPathSet(IEnumerable<string> paths)
{
var stringComparer = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;

assemblyPaths = new(paths, stringComparer);
hashCode = 0;

foreach (var path in assemblyPaths.OrderBy(i => i, stringComparer))
{
hashCode = (hashCode * 397) ^ path.GetHashCode();
}
}

public bool Equals(AssemblyPathSet? other) =>
other is not null && assemblyPaths.SetEquals(other.assemblyPaths);

public override bool Equals(object? obj) =>
obj is AssemblyPathSet other && Equals(other);

public override int GetHashCode() =>
hashCode;
}
11 changes: 6 additions & 5 deletions Fody/Processor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ public partial class Processor
public bool GenerateXsd;
IInnerWeaver? innerWeaver;

static Dictionary<string, IsolatedAssemblyLoadContext> solutionAssemblyLoadContexts =
new(StringComparer.OrdinalIgnoreCase);
static Dictionary<AssemblyPathSet, IsolatedAssemblyLoadContext> loadContexts = new();

public ILogger Logger = null!;
static readonly object mutex = new();
Expand Down Expand Up @@ -147,9 +146,11 @@ void ExecuteInOwnAssemblyLoadContext()

IsolatedAssemblyLoadContext GetLoadContext()
{
if (solutionAssemblyLoadContexts.TryGetValue(SolutionDirectory, out var loadContext))
var assemblyPathSet = new AssemblyPathSet(Weavers.Select(weaver => weaver.AssemblyPath));

if (loadContexts.TryGetValue(assemblyPathSet, out var loadContext))
{
if (!WeaversHistory.HasChanged(Weavers.Select(_ => _.AssemblyPath)))
if (!WeaversHistory.HasChanged(assemblyPathSet.AssemblyPaths))
{
return loadContext;
}
Expand All @@ -158,7 +159,7 @@ IsolatedAssemblyLoadContext GetLoadContext()
loadContext.Unload();
}

return solutionAssemblyLoadContexts[SolutionDirectory] = CreateAssemblyLoadContext();
return loadContexts[assemblyPathSet] = CreateAssemblyLoadContext();
}

IsolatedAssemblyLoadContext CreateAssemblyLoadContext()
Expand Down
22 changes: 14 additions & 8 deletions FodyIsolated/AssemblyLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,20 @@ public Assembly LoadWeaverAssembly(string assemblyPath)
return assemblies[assemblyPath] = LoadFromFile(assemblyPath);
}

// ReSharper disable once MemberCanBeMadeStatic.Local
Assembly LoadFromFile(string assemblyPath)
{
#if(NETSTANDARD)
return LoadContext.LoadNotLocked(assemblyPath);
#else
var rawAssembly = File.ReadAllBytes(assemblyPath);
return Assembly.Load(rawAssembly);
#endif
try
{
#if NETSTANDARD
return LoadContext.LoadNotLocked(assemblyPath);
#else
var rawAssembly = File.ReadAllBytes(assemblyPath);
return Assembly.Load(rawAssembly);
#endif
}
catch (Exception ex)
{
throw new WeavingException($"Could not load weaver assembly from {assemblyPath}: {ex.Message}");
}
}
}
}
23 changes: 23 additions & 0 deletions Tests/Fody/AssemblyPathSetTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Tests.Fody;

public class AssemblyPathSetTests
{
[Fact]
public void ShouldDetectEquality()
{
var a = new AssemblyPathSet(["foo", "bar"]);
var b = new AssemblyPathSet(["bar", "foo", "bar"]);

Assert.Equal(a, b);
Assert.Equal(a.GetHashCode(), b.GetHashCode());
}

[Fact]
public void ShouldDetectInequality()
{
var a = new AssemblyPathSet(["foo", "bar"]);
var b = new AssemblyPathSet(["foo", "baz"]);

Assert.NotEqual(a, b);
}
}

0 comments on commit c4a1446

Please sign in to comment.