Skip to content

Commit

Permalink
Merge pull request #172 from mono/opt-out-alc
Browse files Browse the repository at this point in the history
Add host option to disable AssemblyLoadContext
  • Loading branch information
mhutch authored Jan 11, 2024
2 parents 2257e9e + 79ec659 commit 274037f
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public Assembly LoadInAssemblyLoadContext (AssemblyLoadContext loadContext)
return loadContext.LoadFromStream (new MemoryStream (Assembly));
}
}
#else
#endif
public Assembly LoadInCurrentAppDomain ()
{
if (DebugSymbols != null) {
Expand All @@ -47,6 +47,5 @@ public Assembly LoadInCurrentAppDomain ()
return System.Reflection.Assembly.Load (Assembly);
}
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,51 @@ namespace Mono.TextTemplating;

partial class CompiledTemplate
{
[SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "Same API for ALC and AppDomain build variants of the class")]
sealed class TemplateAssemblyContext : IDisposable
/// <summary>
/// Abstracts over loading assemblies into an AssemblyLoadContext or AppDomain
/// and resolving assemblies from the host.
/// </summary>
abstract class TemplateAssemblyContext : IDisposable
{
public abstract Assembly LoadAssemblyFile (string assemblyPath);
public abstract Assembly LoadInMemoryAssembly (CompiledAssemblyData assemblyData);
public virtual void Dispose () { }

[SuppressMessage ("Performance", "CA1859:Use concrete types when possible for improved performance", Justification = "Conditionally compiled version of this returns multiple concrete types")]

public static TemplateAssemblyContext Create (ITextTemplatingEngineHost host, string[] referenceAssemblyFiles)
{
#if FEATURE_ASSEMBLY_LOAD_CONTEXT
if (!host.IsAssemblyLoadContextDisabled ()) {
return new AssemblyLoadContextTemplateAssemblyContext (host, referenceAssemblyFiles);
}
#endif
return new CurrentAppDomainTemplateAssemblyContext (host, referenceAssemblyFiles);
}
}

#if FEATURE_ASSEMBLY_LOAD_CONTEXT
sealed class AssemblyLoadContextTemplateAssemblyContext : TemplateAssemblyContext
{
readonly TemplateAssemblyLoadContext templateContext;
public TemplateAssemblyContext (ITextTemplatingEngineHost host, string[] referenceAssemblyFiles) => templateContext = new (referenceAssemblyFiles, host);
public Assembly LoadAssemblyFile (string assemblyPath) => templateContext.LoadFromAssemblyPath (assemblyPath);
public Assembly LoadInMemoryAssembly (CompiledAssemblyData assemblyData) => assemblyData.LoadInAssemblyLoadContext (templateContext);
public void Dispose () { }
#else
readonly CurrentDomainAssemblyResolver assemblyResolver;
public TemplateAssemblyContext (ITextTemplatingEngineHost host, string[] referenceAssemblyFiles) => assemblyResolver = new (referenceAssemblyFiles, host.ResolveAssemblyReference);
public Assembly LoadAssemblyFile (string assemblyPath) => Assembly.LoadFile (assemblyPath);
public Assembly LoadInMemoryAssembly (CompiledAssemblyData assemblyData) => assemblyData.LoadInCurrentAppDomain ();
public void Dispose () => assemblyResolver.Dispose ();
public AssemblyLoadContextTemplateAssemblyContext (ITextTemplatingEngineHost host, string[] referenceAssemblyFiles)
=> templateContext = new (referenceAssemblyFiles, host);
public override Assembly LoadAssemblyFile (string assemblyPath) => templateContext.LoadFromAssemblyPath (assemblyPath);
public override Assembly LoadInMemoryAssembly (CompiledAssemblyData assemblyData) => assemblyData.LoadInAssemblyLoadContext (templateContext);
}
#endif

sealed class CurrentAppDomainTemplateAssemblyContext : TemplateAssemblyContext
{
readonly CurrentDomainAssemblyResolver assemblyResolver;
public CurrentAppDomainTemplateAssemblyContext (ITextTemplatingEngineHost host, string[] referenceAssemblyFiles)
=> assemblyResolver = new (referenceAssemblyFiles, host.ResolveAssemblyReference);
public override Assembly LoadAssemblyFile (string assemblyPath) => Assembly.LoadFile (assemblyPath);
public override Assembly LoadInMemoryAssembly (CompiledAssemblyData assemblyData) => assemblyData.LoadInCurrentAppDomain ();
public override void Dispose ()
{
base.Dispose ();
assemblyResolver.Dispose ();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class TemplateProcessor : MarshalByRefObject
[SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "Needs to be an instance for MarshalByRefObject")]
public string CreateAndProcess (ITextTemplatingEngineHost host, CompiledAssemblyData templateAssemblyData, string templateAssemblyFile, string fullName, CultureInfo culture, string[] referencedAssemblyFiles)
{
using var context = new TemplateAssemblyContext (host, referencedAssemblyFiles);
using var context = TemplateAssemblyContext.Create (host, referencedAssemblyFiles);

Assembly assembly = templateAssemblyData is not null
? context.LoadInMemoryAssembly (templateAssemblyData)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#if !FEATURE_ASSEMBLY_LOAD_CONTEXT

using System;
using System.IO;
using System.Reflection;
Expand Down Expand Up @@ -52,5 +50,3 @@ public void Dispose ()
}
}
}

#endif
16 changes: 16 additions & 0 deletions Mono.TextTemplating/Mono.TextTemplating/HostOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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 Microsoft.VisualStudio.TextTemplating;

static class HostOptionExtensions
{
const string DisableAlcOptionName = "DisableAssemblyLoadContext";

static bool IsOptionTrue (this ITextTemplatingEngineHost host, string optionName) =>
host.GetHostOption(optionName) is string optionVal
&& (optionVal == "1" || optionVal.Equals("true", StringComparison.OrdinalIgnoreCase));

public static bool IsAssemblyLoadContextDisabled (this ITextTemplatingEngineHost host) => host.IsOptionTrue (DisableAlcOptionName);
}

0 comments on commit 274037f

Please sign in to comment.