From e823ed9966ac5ac8972a84d77bc5102e5d1c5c85 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 31 Dec 2021 01:54:54 +0100 Subject: [PATCH] #2594: Cache LoadedAssembly.GetTargetFrameworkIdAsync, LoadedAssembly.GetRuntimePackAsync, PEFile.Name, PEFile.FullName to improve performance of assembly resolving. This improves performance of the analysis by a factor of 2. --- ICSharpCode.Decompiler/Metadata/PEFile.cs | 42 +++++++++++++++++------ ILSpy/LoadedAssembly.cs | 34 +++++++++++++----- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/ICSharpCode.Decompiler/Metadata/PEFile.cs b/ICSharpCode.Decompiler/Metadata/PEFile.cs index f2a57ab0f..8368c67ce 100644 --- a/ICSharpCode.Decompiler/Metadata/PEFile.cs +++ b/ICSharpCode.Decompiler/Metadata/PEFile.cs @@ -72,8 +72,38 @@ namespace ICSharpCode.Decompiler.Metadata } public bool IsAssembly => Metadata.IsAssembly; - public string Name => GetName(); - public string FullName => IsAssembly ? Metadata.GetFullAssemblyName() : Name; + + string? name; + + public string Name { + get { + var value = LazyInit.VolatileRead(ref name); + if (value == null) + { + var metadata = Metadata; + value = metadata.IsAssembly + ? metadata.GetString(metadata.GetAssemblyDefinition().Name) + : metadata.GetString(metadata.GetModuleDefinition().Name); + value = LazyInit.GetOrSet(ref name, value); + } + return value; + } + } + + string? fullName; + + public string FullName { + get { + var value = LazyInit.VolatileRead(ref fullName); + if (value == null) + { + var metadata = Metadata; + value = metadata.IsAssembly ? metadata.GetFullAssemblyName() : Name; + value = LazyInit.GetOrSet(ref fullName, value); + } + return value; + } + } public TargetRuntime GetRuntime() { @@ -98,14 +128,6 @@ namespace ICSharpCode.Decompiler.Metadata } } - string GetName() - { - var metadata = Metadata; - if (metadata.IsAssembly) - return metadata.GetString(metadata.GetAssemblyDefinition().Name); - return metadata.GetString(metadata.GetModuleDefinition().Name); - } - public ImmutableArray AssemblyReferences => Metadata.AssemblyReferences.Select(r => new AssemblyReference(this, r)).ToImmutableArray(); public ImmutableArray Resources => GetResources().ToImmutableArray(); diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs index 320a7f581..cad1fb69f 100644 --- a/ILSpy/LoadedAssembly.cs +++ b/ILSpy/LoadedAssembly.cs @@ -107,22 +107,41 @@ namespace ICSharpCode.ILSpy this.ParentBundle = bundle; } + string? targetFrameworkId; + /// /// Returns a target framework identifier in the form '<framework>Version=v<version>'. - /// Returns an empty string if no TargetFrameworkAttribute was found or the file doesn't contain an assembly header, i.e., is only a module. + /// Returns an empty string if no TargetFrameworkAttribute was found + /// or the file doesn't contain an assembly header, i.e., is only a module. /// /// Throws an exception if the file does not contain any .NET metadata (e.g. file of unknown format). /// public async Task GetTargetFrameworkIdAsync() { - var assembly = await GetPEFileAsync().ConfigureAwait(false); - return assembly.DetectTargetFrameworkId() ?? string.Empty; + var value = LazyInit.VolatileRead(ref targetFrameworkId); + if (value == null) + { + var assembly = await GetPEFileAsync().ConfigureAwait(false); + value = assembly.DetectTargetFrameworkId() ?? string.Empty; + value = LazyInit.GetOrSet(ref targetFrameworkId, value); + } + + return value; } + string? runtimePack; + public async Task GetRuntimePackAsync() { - var assembly = await GetPEFileAsync().ConfigureAwait(false); - return assembly.DetectRuntimePack() ?? string.Empty; + var value = LazyInit.VolatileRead(ref runtimePack); + if (value == null) + { + var assembly = await GetPEFileAsync().ConfigureAwait(false); + value = assembly.DetectRuntimePack() ?? string.Empty; + value = LazyInit.GetOrSet(ref runtimePack, value); + } + + return value; } public ReferenceLoadInfo LoadedAssemblyReferencesInfo { get; } = new ReferenceLoadInfo(); @@ -588,10 +607,9 @@ namespace ICSharpCode.ILSpy var reader = module.Metadata; if (reader == null || !reader.IsAssembly) continue; - var asmDef = reader.GetAssemblyDefinition(); - string tfm = await loaded.GetTargetFrameworkIdAsync(); + string tfm = await loaded.GetTargetFrameworkIdAsync().ConfigureAwait(false); string key = tfm + ";" - + (shortNames ? reader.GetString(asmDef.Name) : reader.GetFullAssemblyName()); + + (shortNames ? module.Name : module.FullName); if (!result.ContainsKey(key)) { result.Add(key, module);