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

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

@ -17,14 +17,11 @@ namespace ICSharpCode.ILSpyAddIn
public class ILSpyFullParseInformation : ParseInformation public class ILSpyFullParseInformation : ParseInformation
{ {
SyntaxTree syntaxTree; 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) : base(unresolvedFile, parsedVersion, true)
{ {
this.syntaxTree = syntaxTree; this.syntaxTree = syntaxTree;
this.neededAssemblies = neededAssemblies.ToArray();
} }
public SyntaxTree SyntaxTree { get { return syntaxTree; } } public SyntaxTree SyntaxTree { get { return syntaxTree; } }

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

@ -55,16 +55,6 @@ namespace ICSharpCode.ILSpyAddIn
throw new NotImplementedException(); 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) public ICompilation CreateCompilationForSingleFile(FileName fileName, IUnresolvedFile unresolvedFile)
{ {
DecompiledTypeReference reference = DecompiledTypeReference.FromFileName(fileName); DecompiledTypeReference reference = DecompiledTypeReference.FromFileName(fileName);
@ -73,10 +63,9 @@ namespace ICSharpCode.ILSpyAddIn
if (model == null) if (model == null)
model = SD.AssemblyParserService.GetAssemblyModelSafe(reference.AssemblyFile, true); model = SD.AssemblyParserService.GetAssemblyModelSafe(reference.AssemblyFile, true);
if (model != null) if (model != null)
return SD.AssemblyParserService.CreateCompilationForAssembly(model, true); return model.Context.GetCompilation();
} }
return new CSharpProjectContent() return new CSharpProjectContent()
.AddAssemblyReferences(defaultReferences.Value)
.AddOrUpdateFiles(unresolvedFile) .AddOrUpdateFiles(unresolvedFile)
.CreateCompilation(); .CreateCompilation();
} }

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

@ -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 public class AssemblyEntityModelContext : IEntityModelContext
{ {
ICompilation compilation; Lazy<ICompilation> compilation;
IUnresolvedAssembly mainAssembly; IUnresolvedAssembly mainAssembly;
IAssemblyReference[] references; IAssemblyReference[] references;
public AssemblyEntityModelContext(IUnresolvedAssembly mainAssembly, params IAssemblyReference[] references) public AssemblyEntityModelContext(IUnresolvedAssembly mainAssembly, IAssemblyReference[] references)
{ {
if (mainAssembly == null) if (mainAssembly == null)
throw new ArgumentNullException("mainAssembly"); throw new ArgumentNullException("mainAssembly");
this.mainAssembly = mainAssembly; this.mainAssembly = mainAssembly;
this.references = references; this.references = references;
// implement lazy init + weak caching this.compilation = new Lazy<ICompilation>(() => new SimpleCompilation(mainAssembly, references));
this.compilation = new SimpleCompilation(mainAssembly, references);
} }
public string AssemblyName { public string AssemblyName {
@ -117,7 +137,7 @@ namespace ICSharpCode.SharpDevelop.Dom
public ICompilation GetCompilation() public ICompilation GetCompilation()
{ {
return compilation; return compilation.Value;
} }
public bool IsBetterPart(IUnresolvedTypeDefinition part1, IUnresolvedTypeDefinition part2) public bool IsBetterPart(IUnresolvedTypeDefinition part1, IUnresolvedTypeDefinition part2)

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

@ -51,16 +51,6 @@ namespace ICSharpCode.SharpDevelop.Parser
event EventHandler<RefreshAssemblyEventArgs> AssemblyRefreshed; 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> /// <summary>
/// Creates an IAssemblyModel for the given assembly file. /// Creates an IAssemblyModel for the given assembly file.
/// </summary> /// </summary>

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

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

Loading…
Cancel
Save