Browse Source

use ModuleDefinition in ILSpyDecompilerService cache; remove CreateCompilationForAssembly

newNRILSpyDebugger
Siegfried Pammer 12 years ago
parent
commit
b8cd4f3d7a
  1. 78
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyDecompilerService.cs
  2. 5
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyFullParseInformation.cs
  3. 13
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyParser.cs
  4. 30
      src/Main/Base/Project/Dom/IEntityModelContext.cs
  5. 10
      src/Main/Base/Project/Parser/IAssemblyParserService.cs
  6. 36
      src/Main/SharpDevelop/Parser/AssemblyParserService.cs

78
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyDecompilerService.cs

@ -23,45 +23,46 @@ namespace ICSharpCode.ILSpyAddIn @@ -23,45 +23,46 @@ namespace ICSharpCode.ILSpyAddIn
/// </summary>
public static class ILSpyDecompilerService
{
class AssemblyCacheInfo
class ModuleCacheInfo
{
public readonly DateTime LastUpdateTime;
public readonly WeakReference<AssemblyDefinition> Assembly;
public readonly WeakReference<ModuleDefinition> Module;
public AssemblyCacheInfo(DateTime lastUpdateTime, AssemblyDefinition assembly)
public ModuleCacheInfo(DateTime lastUpdateTime, ModuleDefinition assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
this.LastUpdateTime = lastUpdateTime;
this.Assembly = new WeakReference<AssemblyDefinition>(assembly);
this.Module = new WeakReference<ModuleDefinition>(assembly);
}
}
static readonly Dictionary<FileName, AssemblyCacheInfo> assemblyCache = new Dictionary<FileName, AssemblyCacheInfo>();
static readonly Dictionary<FileName, ModuleCacheInfo> moduleCache = new Dictionary<FileName, ModuleCacheInfo>();
static AssemblyDefinition GetAssemblyDefinitionFromCache(FileName file, ReaderParameters parameters = null)
static ModuleDefinition GetModuleDefinitionFromCache(FileName file)
{
if (file == null) return null;
if (parameters == null) parameters = new ReaderParameters();
ReaderParameters parameters = new ReaderParameters();
var resolver = new ILSpyAssemblyResolver(file);
var lastUpdateTime = File.GetLastWriteTimeUtc(file);
lock (assemblyCache) {
AssemblyCacheInfo info;
AssemblyDefinition asm;
if (!assemblyCache.TryGetValue(file, out info)) {
asm = AssemblyDefinition.ReadAssembly(file, parameters);
assemblyCache.Add(file, new AssemblyCacheInfo(lastUpdateTime, asm));
return asm;
lock (moduleCache) {
ModuleCacheInfo info;
ModuleDefinition module;
if (!moduleCache.TryGetValue(file, out info)) {
module = ModuleDefinition.ReadModule(file, parameters);
moduleCache.Add(file, new ModuleCacheInfo(lastUpdateTime, module));
return module;
} else if (info.LastUpdateTime < lastUpdateTime) {
assemblyCache.Remove(file);
asm = AssemblyDefinition.ReadAssembly(file, parameters);
assemblyCache.Add(file, new AssemblyCacheInfo(lastUpdateTime, asm));
return asm;
moduleCache.Remove(file);
module = ModuleDefinition.ReadModule(file, parameters);
moduleCache.Add(file, new ModuleCacheInfo(lastUpdateTime, module));
return module;
} else {
if (info.Assembly.TryGetTarget(out asm))
return asm;
asm = AssemblyDefinition.ReadAssembly(file, parameters);
info.Assembly.SetTarget(asm);
return asm;
if (info.Module.TryGetTarget(out module))
return module;
module = ModuleDefinition.ReadModule(file, parameters);
info.Module.SetTarget(module);
return module;
}
}
}
@ -77,14 +78,19 @@ namespace ICSharpCode.ILSpyAddIn @@ -77,14 +78,19 @@ namespace ICSharpCode.ILSpyAddIn
{
}
/// <summary>
/// Used to remember the referenced assemblies for the WeakReference cache policy.
/// </summary>
readonly ISet<AssemblyDefinition> resolvedAssemblies = new HashSet<AssemblyDefinition>();
AssemblyDefinition Resolve(DomAssemblyName name, ReaderParameters parameters)
{
var assemblyDefinition = GetAssemblyDefinitionFromCache(FindAssembly(name), parameters);
if (assemblyDefinition != null)
resolvedAssemblies.Add(assemblyDefinition);
return assemblyDefinition;
var moduleDefinition = GetModuleDefinitionFromCache(FindAssembly(name));
if (moduleDefinition != null) {
resolvedAssemblies.Add(moduleDefinition.Assembly);
return moduleDefinition.Assembly;
}
return null;
}
public AssemblyDefinition Resolve(AssemblyNameReference name)
@ -111,7 +117,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -111,7 +117,7 @@ namespace ICSharpCode.ILSpyAddIn
public static ILSpyUnresolvedFile DecompileType(DecompiledTypeReference name)
{
if (name == null)
throw new ArgumentNullException("entity");
throw new ArgumentNullException("name");
return DoDecompile(name);
}
@ -122,17 +128,16 @@ namespace ICSharpCode.ILSpyAddIn @@ -122,17 +128,16 @@ namespace ICSharpCode.ILSpyAddIn
cancellationToken);
}
static AstBuilder CreateAstBuilder(DecompiledTypeReference name, out AssemblyDefinition[] neededAssemblies, CancellationToken cancellationToken = default(CancellationToken))
static AstBuilder CreateAstBuilder(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
ReaderParameters readerParameters = new ReaderParameters();
// Use new assembly resolver instance so that the AssemblyDefinitions
// can be garbage-collected once the code is decompiled.
var resolver = new ILSpyAssemblyResolver(name.AssemblyFile);
readerParameters.AssemblyResolver = resolver;
AssemblyDefinition asm = GetAssemblyDefinitionFromCache(name.AssemblyFile, readerParameters);
if (asm == null)
ModuleDefinition module = GetModuleDefinitionFromCache(name.AssemblyFile);
if (module == null)
throw new InvalidOperationException("Could not find assembly file");
ModuleDefinition module = asm.MainModule;
TypeDefinition typeDefinition = module.GetType(name.Type.ReflectionName);
if (typeDefinition == null)
throw new InvalidOperationException("Could not find type");
@ -140,21 +145,18 @@ namespace ICSharpCode.ILSpyAddIn @@ -140,21 +145,18 @@ namespace ICSharpCode.ILSpyAddIn
context.CancellationToken = cancellationToken;
AstBuilder astBuilder = new AstBuilder(context);
astBuilder.AddType(typeDefinition);
neededAssemblies = resolver.ResolvedAssemblies.ToArray();
return astBuilder;
}
static ILSpyUnresolvedFile DoDecompile(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
AssemblyDefinition[] assemblies;
return ILSpyUnresolvedFile.Create(name, CreateAstBuilder(name, out assemblies, cancellationToken));
return ILSpyUnresolvedFile.Create(name, CreateAstBuilder(name, cancellationToken));
}
public static ILSpyFullParseInformation ParseDecompiledType(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
AssemblyDefinition[] assemblies;
var astBuilder = CreateAstBuilder(name, out assemblies, cancellationToken);
return new ILSpyFullParseInformation(ILSpyUnresolvedFile.Create(name, astBuilder), null, astBuilder.SyntaxTree, assemblies);
var astBuilder = CreateAstBuilder(name, cancellationToken);
return new ILSpyFullParseInformation(ILSpyUnresolvedFile.Create(name, astBuilder), null, astBuilder.SyntaxTree);
}
}

5
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyFullParseInformation.cs

@ -17,14 +17,11 @@ namespace ICSharpCode.ILSpyAddIn @@ -17,14 +17,11 @@ namespace ICSharpCode.ILSpyAddIn
public class ILSpyFullParseInformation : ParseInformation
{
SyntaxTree syntaxTree;
// Required to make WeakReferences work properly as cache policy.
AssemblyDefinition[] neededAssemblies;
public ILSpyFullParseInformation(ILSpyUnresolvedFile unresolvedFile, ITextSourceVersion parsedVersion, SyntaxTree syntaxTree, IEnumerable<AssemblyDefinition> neededAssemblies)
public ILSpyFullParseInformation(ILSpyUnresolvedFile unresolvedFile, ITextSourceVersion parsedVersion, SyntaxTree syntaxTree)
: base(unresolvedFile, parsedVersion, true)
{
this.syntaxTree = syntaxTree;
this.neededAssemblies = neededAssemblies.ToArray();
}
public SyntaxTree SyntaxTree { get { return syntaxTree; } }

13
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyParser.cs

@ -55,16 +55,6 @@ namespace ICSharpCode.ILSpyAddIn @@ -55,16 +55,6 @@ namespace ICSharpCode.ILSpyAddIn
throw new NotImplementedException();
}
static readonly Lazy<IAssemblyReference[]> defaultReferences = new Lazy<IAssemblyReference[]>(
delegate {
Assembly[] assemblies = {
typeof(object).Assembly,
typeof(Uri).Assembly,
typeof(Enumerable).Assembly
};
return assemblies.Select(asm => new CecilLoader().LoadAssemblyFile(asm.Location)).ToArray();
});
public ICompilation CreateCompilationForSingleFile(FileName fileName, IUnresolvedFile unresolvedFile)
{
DecompiledTypeReference reference = DecompiledTypeReference.FromFileName(fileName);
@ -73,10 +63,9 @@ namespace ICSharpCode.ILSpyAddIn @@ -73,10 +63,9 @@ namespace ICSharpCode.ILSpyAddIn
if (model == null)
model = SD.AssemblyParserService.GetAssemblyModelSafe(reference.AssemblyFile, true);
if (model != null)
return SD.AssemblyParserService.CreateCompilationForAssembly(model, true);
return model.Context.GetCompilation();
}
return new CSharpProjectContent()
.AddAssemblyReferences(defaultReferences.Value)
.AddOrUpdateFiles(unresolvedFile)
.CreateCompilation();
}

30
src/Main/Base/Project/Dom/IEntityModelContext.cs

@ -91,20 +91,40 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -91,20 +91,40 @@ namespace ICSharpCode.SharpDevelop.Dom
}
}
public class DomAssemblyNameReference : IAssemblyReference
{
DomAssemblyName name;
IAssemblySearcher searcher;
public DomAssemblyNameReference(DomAssemblyName name, IAssemblySearcher searcher)
{
if (name == null)
throw new ArgumentNullException("name");
if (searcher == null)
throw new ArgumentNullException("searcher");
this.name = name;
this.searcher = searcher;
}
public IAssembly Resolve(ITypeResolveContext context)
{
return SD.AssemblyParserService.GetAssembly(searcher.FindAssembly(name), true).Resolve(context);
}
}
public class AssemblyEntityModelContext : IEntityModelContext
{
ICompilation compilation;
Lazy<ICompilation> compilation;
IUnresolvedAssembly mainAssembly;
IAssemblyReference[] references;
public AssemblyEntityModelContext(IUnresolvedAssembly mainAssembly, params IAssemblyReference[] references)
public AssemblyEntityModelContext(IUnresolvedAssembly mainAssembly, IAssemblyReference[] references)
{
if (mainAssembly == null)
throw new ArgumentNullException("mainAssembly");
this.mainAssembly = mainAssembly;
this.references = references;
// implement lazy init + weak caching
this.compilation = new SimpleCompilation(mainAssembly, references);
this.compilation = new Lazy<ICompilation>(() => new SimpleCompilation(mainAssembly, references));
}
public string AssemblyName {
@ -117,7 +137,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -117,7 +137,7 @@ namespace ICSharpCode.SharpDevelop.Dom
public ICompilation GetCompilation()
{
return compilation;
return compilation.Value;
}
public bool IsBetterPart(IUnresolvedTypeDefinition part1, IUnresolvedTypeDefinition part2)

10
src/Main/Base/Project/Parser/IAssemblyParserService.cs

@ -51,16 +51,6 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -51,16 +51,6 @@ namespace ICSharpCode.SharpDevelop.Parser
event EventHandler<RefreshAssemblyEventArgs> AssemblyRefreshed;
/// <summary>
/// Creates a compilation for the specified assembly.
/// </summary>
ICompilation CreateCompilationForAssembly(IAssemblyModel assembly, bool includeInternalMembers = false);
/// <summary>
/// Creates a compilation for the specified assembly.
/// </summary>
ICompilation CreateCompilationForAssembly(FileName assembly, bool includeInternalMembers = false);
/// <summary>
/// Creates an IAssemblyModel for the given assembly file.
/// </summary>

36
src/Main/SharpDevelop/Parser/AssemblyParserService.cs

@ -82,14 +82,14 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -82,14 +82,14 @@ namespace ICSharpCode.SharpDevelop.Parser
void CleanWeakDictionary()
{
Debug.Assert(Monitor.IsEntered(projectContentDictionary));
List<FileName> removed = new List<FileName>();
foreach (var pair in projectContentDictionary) {
//if (!pair.Value.IsAlive)
// removed.Add(pair.Key);
}
foreach (var key in removed)
projectContentDictionary.Remove(key);
// Debug.Assert(Monitor.IsEntered(projectContentDictionary));
// List<FileName> removed = new List<FileName>();
// foreach (var pair in projectContentDictionary) {
// if (!pair.Value.IsAlive)
// removed.Add(pair.Key);
// }
// foreach (var key in removed)
// projectContentDictionary.Remove(key);
}
LoadedAssembly GetLoadedAssembly(FileName fileName, bool includeInternalMembers)
@ -326,26 +326,12 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -326,26 +326,12 @@ namespace ICSharpCode.SharpDevelop.Parser
}
#endregion
public ICompilation CreateCompilationForAssembly(IAssemblyModel assembly, bool includeInternalMembers = false)
{
var mainAssembly = GetAssembly(assembly.Location, includeInternalMembers);
var searcher = new DefaultAssemblySearcher(assembly.Location);
var references = assembly.References
.Select(searcher.FindAssembly)
.Where(f => f != null);
return new SimpleCompilation(mainAssembly, references.Select(fn => GetAssembly(fn, includeInternalMembers)));
}
public ICompilation CreateCompilationForAssembly(FileName assembly, bool includeInternalMembers = false)
{
return CreateCompilationForAssembly(GetAssemblyModel(assembly, includeInternalMembers), includeInternalMembers);
}
public IAssemblyModel GetAssemblyModel(FileName fileName, bool includeInternalMembers = false)
{
LoadedAssembly assembly = GetLoadedAssembly(fileName, includeInternalMembers);
// TODO context might need references as well
IEntityModelContext context = new AssemblyEntityModelContext(assembly.ProjectContent);
IEntityModelContext context = new AssemblyEntityModelContext(
assembly.ProjectContent,
assembly.References.Select(name => new DomAssemblyNameReference(name, new DefaultAssemblySearcher(fileName))).ToArray());
IUpdateableAssemblyModel model = SD.GetService<IModelFactory>().CreateAssemblyModel(context);
model.Update(EmptyList<IUnresolvedTypeDefinition>.Instance, assembly.ProjectContent.TopLevelTypeDefinitions.ToList());

Loading…
Cancel
Save