Skip to content

Commit

Permalink
Merge pull request #54 from jnm2/faster_resolver
Browse files Browse the repository at this point in the history
Use stripped-down resolver for perf (no GAC, deferred reading mode)
  • Loading branch information
sharwell authored Jan 5, 2020
2 parents 4951f6e + bc2840b commit c14d291
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 12 deletions.
9 changes: 8 additions & 1 deletion CecilBasedAnnotator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@

namespace CecilBasedAnnotator
{
using System.Collections.Immutable;

internal class Program
{
private static void Main(string[] args)
{
TunnelVisionLabs.ReferenceAssemblyAnnotator.Program.Main(log: null, args[0], args[1], args[2]);
TunnelVisionLabs.ReferenceAssemblyAnnotator.Program.Main(
log: null,
referenceAssembly: args[0],
targetFrameworkDirectories: args[1].Split(';').ToImmutableArray(),
annotatedReferenceAssembly: args[2],
outputAssembly: args[3]);
}
}
}
10 changes: 5 additions & 5 deletions CecilBasedAnnotator/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"profiles": {
"mscorlib": {
"Microsoft.Win32.Primitives (netstandard1.6)": {
"commandName": "Project",
"commandLineArgs": "\"$(NuGetPackageRoot)\\microsoft.netframework.referenceassemblies.net45\\1.0.0-preview.2\\build\\.NETFramework\\v4.5\\mscorlib.dll\" \"$(NuGetPackageRoot)\\microsoft.netcore.app.ref\\3.0.0-preview8-28405-07\\ref\\netcoreapp3.0\\mscorlib.dll\" mscorlib2.dll"
"commandLineArgs": "\"$(NuGetPackageRoot)\\microsoft.win32.primitives\\4.3.0\\ref\\netstandard1.3\\Microsoft.Win32.Primitives.dll\" \"$(NuGetPackageRoot)\\microsoft.win32.primitives\\4.3.0\\ref\\netstandard1.3\\;$(NuGetPackageRoot)\\system.runtime\\4.3.0\\ref\\netstandard1.5\\\\\" \"$(NuGetPackageRoot)\\microsoft.netcore.app.ref\\3.0.0\\ref\\netcoreapp3.0\\Microsoft.Win32.Primitives.dll\" Microsoft.Win32.Primitives.dll"
},
"System": {
"System.ComponentModel.DataAnnotations (netcoreapp2.0)": {
"commandName": "Project",
"commandLineArgs": "\"$(NuGetPackageRoot)\\microsoft.netframework.referenceassemblies.net45\\1.0.0-preview.2\\build\\.NETFramework\\v4.5\\System.dll\" \"$(NuGetPackageRoot)\\microsoft.netcore.app.ref\\3.0.0-preview8-28405-07\\ref\\netcoreapp3.0\\System.dll\" System2.dll"
"commandLineArgs": "\"$(NuGetPackageRoot)\\microsoft.netcore.app\\2.0.0\\ref\\netcoreapp2.0\\System.ComponentModel.DataAnnotations.dll\" \"$(NuGetPackageRoot)\\microsoft.netcore.app\\2.0.0\\ref\\netcoreapp2.0\\\\\" \"$(NuGetPackageRoot)\\microsoft.netcore.app.ref\\3.0.0\\ref\\netcoreapp3.0\\System.ComponentModel.DataAnnotations.dll\" System.ComponentModel.DataAnnotations.dll"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace TunnelVisionLabs.ReferenceAssemblyAnnotator
{
using System;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using Microsoft.Build.Framework;
Expand Down Expand Up @@ -96,7 +97,14 @@ public override bool Execute()

Directory.CreateDirectory(OutputPath);
string outputAssembly = Path.Combine(OutputPath, Path.GetFileName(unannotatedReferenceAssembly));
Program.Main(log, unannotatedReferenceAssembly, annotatedReferenceAssembly, outputAssembly);

Program.Main(
log,
unannotatedReferenceAssembly,
TargetFrameworkDirectories.Select(item => item.ItemSpec).ToImmutableArray(),
annotatedReferenceAssembly,
outputAssembly);

GeneratedAssemblies = new[] { new TaskItem(outputAssembly) };

string sourceDocumentation = Path.ChangeExtension(unannotatedReferenceAssembly, ".xml");
Expand Down
77 changes: 77 additions & 0 deletions TunnelVisionLabs.ReferenceAssemblyAnnotator/AssemblyResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

namespace TunnelVisionLabs.ReferenceAssemblyAnnotator
{
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using Mono.Cecil;

internal sealed class AssemblyResolver : IAssemblyResolver
{
private static readonly ReaderParameters DefaultReaderParameters = new ReaderParameters(ReadingMode.Deferred);

private readonly ImmutableArray<string> _searchDirectories;
private readonly Dictionary<string, AssemblyDefinition?> _assembliesByFileName = new Dictionary<string, AssemblyDefinition?>();

public AssemblyResolver(ImmutableArray<string> searchDirectories)
{
_searchDirectories = searchDirectories;
}

public AssemblyDefinition? Resolve(AssemblyNameReference name)
{
return Resolve(name, DefaultReaderParameters);
}

public AssemblyDefinition? Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
if (!_assembliesByFileName.TryGetValue(name.Name, out var assembly))
{
var stream = _searchDirectories
.Select(directory => OpenReadIfExists(Path.Combine(directory, name.Name + ".dll")))
.FirstOrDefault(s => s is object);

assembly = stream is null ? null : AssemblyDefinition.ReadAssembly(stream, parameters);

_assembliesByFileName.Add(name.Name, assembly);
}

return assembly is object && Matches(assembly.Name, name) ? assembly : null;
}

private static FileStream? OpenReadIfExists(string path)
{
try
{
return File.OpenRead(path);
}
catch (FileNotFoundException)
{
return null;
}
}

/// <summary>
/// The point of this method is to be a high-performance sanity check, not to reproduce .NET assembly loading
/// behavior.
/// </summary>
private static bool Matches(AssemblyNameDefinition definition, AssemblyNameReference reference)
{
return definition.Name == reference.Name
&& definition.Version >= reference.Version;
}

public void Dispose()
{
foreach (var loadedAssembly in _assembliesByFileName.Values)
{
loadedAssembly?.Dispose();
}

_assembliesByFileName.Clear();
}
}
}
15 changes: 10 additions & 5 deletions TunnelVisionLabs.ReferenceAssemblyAnnotator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace TunnelVisionLabs.ReferenceAssemblyAnnotator
{
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
Expand All @@ -13,10 +14,9 @@ namespace TunnelVisionLabs.ReferenceAssemblyAnnotator

internal class Program
{
internal static void Main(SuppressibleLoggingHelper? log, string referenceAssembly, string annotatedReferenceAssembly, string outputAssembly)
internal static void Main(SuppressibleLoggingHelper? log, string referenceAssembly, ImmutableArray<string> targetFrameworkDirectories, string annotatedReferenceAssembly, string outputAssembly)
{
var assemblyResolver = new DefaultAssemblyResolver();
assemblyResolver.AddSearchDirectory(Path.GetDirectoryName(referenceAssembly));
using var assemblyResolver = new AssemblyResolver(targetFrameworkDirectories);
using var assemblyDefinition = AssemblyDefinition.ReadAssembly(referenceAssembly, new ReaderParameters(ReadingMode.Deferred) { AssemblyResolver = assemblyResolver });

foreach (var module in assemblyDefinition.Modules)
Expand All @@ -26,10 +26,15 @@ internal static void Main(SuppressibleLoggingHelper? log, string referenceAssemb
log?.LogWarning("RA1000", "Skipping mixed-mode implementation assembly '{0}'", assemblyDefinition.Name);
return;
}

if (module.TypeSystem.Object.Resolve() is null)
{
log?.LogWarning("RA1001", "Cannot resolve core library for assembly '{0}', skipping", assemblyDefinition.Name);
return;
}
}

var annotatedAssemblyResolver = new DefaultAssemblyResolver();
annotatedAssemblyResolver.AddSearchDirectory(Path.GetDirectoryName(annotatedReferenceAssembly));
using var annotatedAssemblyResolver = new AssemblyResolver(ImmutableArray.Create(Path.GetDirectoryName(Path.GetFullPath(annotatedReferenceAssembly))!));
using var annotatedAssemblyDefinition = AssemblyDefinition.ReadAssembly(annotatedReferenceAssembly, new ReaderParameters(ReadingMode.Deferred) { AssemblyResolver = annotatedAssemblyResolver });

var wellKnownTypes = new WellKnownTypes(assemblyDefinition);
Expand Down

0 comments on commit c14d291

Please sign in to comment.