Browse Source

Add TypeSystemOptions.Uncached.

pull/1030/head
Daniel Grunwald 7 years ago
parent
commit
ab157b2fc0
  1. 6
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  3. 2
      ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs
  4. 22
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  5. 12
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs
  6. 34
      ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs
  7. 7
      ILSpy/LoadedAssembly.cs
  8. 3
      ILSpy/MainWindow.xaml.cs
  9. 2
      ILSpy/TextView/DecompilerTextView.cs
  10. 3
      ILSpy/TreeNodes/BaseTypesEntryNode.cs

6
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -395,12 +395,14 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -395,12 +395,14 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
public static string DecompileCSharp(string assemblyFileName, DecompilerSettings settings = null)
{
if (settings == null)
settings = new DecompilerSettings();
using (var file = new FileStream(assemblyFileName, FileMode.Open, FileAccess.Read)) {
var module = new PEFile(assemblyFileName, file, PEStreamOptions.PrefetchEntireImage);
var resolver = new UniversalAssemblyResolver(assemblyFileName, false,
module.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchMetadata);
var typeSystem = new DecompilerTypeSystem(module, resolver);
CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, settings ?? new DecompilerSettings());
var typeSystem = new DecompilerTypeSystem(module, resolver, settings);
CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, settings);
decompiler.AstTransforms.Insert(0, new RemoveEmbeddedAtttributes());
decompiler.AstTransforms.Insert(0, new RemoveCompilerAttribute());
decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers());

2
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -225,6 +225,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -225,6 +225,8 @@ namespace ICSharpCode.Decompiler.CSharp
this.settings = settings;
this.module = typeSystem.MainModule;
this.metadata = module.PEFile.Metadata;
if (module.TypeSystemOptions.HasFlag(TypeSystemOptions.Uncached))
throw new ArgumentException("Cannot use an uncached type system in the decompiler.");
}
#region MemberIsHidden

2
ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

@ -317,7 +317,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -317,7 +317,7 @@ namespace ICSharpCode.Decompiler.CSharp
return Path.Combine(dir, file);
}
}, StringComparer.OrdinalIgnoreCase).ToList();
DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver);
DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver, settings);
Parallel.ForEach(
files,
new ParallelOptions {

22
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -63,6 +63,16 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -63,6 +63,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
OnlyPublicAPI = 8,
/// <summary>
/// Do not cache accessed entities.
/// In a normal type system (without this option), every type or member definition has exactly one ITypeDefinition/IMember
/// instance. This instance is kept alive until the whole type system can be garbage-collected.
/// When this option is specified, the type system avoids these caches.
/// This reduces the memory usage in many cases, but increases the number of allocations.
/// Also, some code in the decompiler expects to be able to compare type/member definitions by reference equality,
/// and thus will fail with uncached type systems.
/// </summary>
Uncached = 0x10,
/// <summary>
/// Default settings: all features enabled.
/// </summary>
Default = Dynamic | Tuple | ExtensionMethods
@ -76,12 +86,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -76,12 +86,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </remarks>
public class DecompilerTypeSystem : SimpleCompilation, IDecompilerTypeSystem
{
public DecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver)
: this(mainModule, assemblyResolver, TypeSystemOptions.Default)
{
}
static TypeSystemOptions GetOptions(DecompilerSettings settings)
public static TypeSystemOptions GetOptions(DecompilerSettings settings)
{
var typeSystemOptions = TypeSystemOptions.None;
if (settings.Dynamic)
@ -93,6 +98,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -93,6 +98,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
return typeSystemOptions;
}
public DecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver)
: this(mainModule, assemblyResolver, TypeSystemOptions.Default)
{
}
public DecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver, DecompilerSettings settings)
: this(mainModule, assemblyResolver, GetOptions(settings ?? throw new ArgumentNullException(nameof(settings))))
{

12
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs

@ -127,6 +127,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -127,6 +127,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
foreach (TypeDefinitionHandle h in nestedTypeCollection) {
nestedTypeList.Add(module.GetDefinition(h));
}
if ((module.TypeSystemOptions & TypeSystemOptions.Uncached) != 0)
return nestedTypeList;
return LazyInit.GetOrSet(ref this.nestedTypes, nestedTypeList.ToArray());
}
}
@ -138,6 +140,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -138,6 +140,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
if (members != null)
return members;
members = this.Fields.Concat<IMember>(this.Methods).Concat(this.Properties).Concat(this.Events).ToArray();
if ((module.TypeSystemOptions & TypeSystemOptions.Uncached) != 0)
return members;
return LazyInit.GetOrSet(ref this.members, members);
}
}
@ -157,6 +161,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -157,6 +161,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
fieldList.Add(module.GetDefinition(h));
}
}
if ((module.TypeSystemOptions & TypeSystemOptions.Uncached) != 0)
return fieldList;
return LazyInit.GetOrSet(ref this.fields, fieldList.ToArray());
}
}
@ -178,6 +184,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -178,6 +184,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
propertyList.Add(module.GetDefinition(h));
}
}
if ((module.TypeSystemOptions & TypeSystemOptions.Uncached) != 0)
return propertyList;
return LazyInit.GetOrSet(ref this.properties, propertyList.ToArray());
}
}
@ -200,6 +208,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -200,6 +208,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
eventList.Add(module.GetDefinition(h));
}
}
if ((module.TypeSystemOptions & TypeSystemOptions.Uncached) != 0)
return eventList;
return LazyInit.GetOrSet(ref this.events, eventList.ToArray());
}
}
@ -222,6 +232,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -222,6 +232,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
if (this.Kind == TypeKind.Struct || this.Kind == TypeKind.Enum) {
methodsList.Add(FakeMethod.CreateDummyConstructor(Compilation, this, IsAbstract ? Accessibility.Protected : Accessibility.Public));
}
if ((module.TypeSystemOptions & TypeSystemOptions.Uncached) != 0)
return methodsList;
return LazyInit.GetOrSet(ref this.methods, methodsList.ToArray());
}
}

34
ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs

@ -68,12 +68,14 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -68,12 +68,14 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
this.rootNamespace = new MetadataNamespace(this, null, string.Empty, metadata.GetNamespaceDefinitionRoot());
// create arrays for resolved entities, indexed by row index
this.typeDefs = new MetadataTypeDefinition[metadata.TypeDefinitions.Count + 1];
this.fieldDefs = new MetadataField[metadata.FieldDefinitions.Count + 1];
this.methodDefs = new MetadataMethod[metadata.MethodDefinitions.Count + 1];
this.propertyDefs = new MetadataProperty[metadata.PropertyDefinitions.Count + 1];
this.eventDefs = new MetadataEvent[metadata.EventDefinitions.Count + 1];
if (!options.HasFlag(TypeSystemOptions.Uncached)) {
// create arrays for resolved entities, indexed by row index
this.typeDefs = new MetadataTypeDefinition[metadata.TypeDefinitions.Count + 1];
this.fieldDefs = new MetadataField[metadata.FieldDefinitions.Count + 1];
this.methodDefs = new MetadataMethod[metadata.MethodDefinitions.Count + 1];
this.propertyDefs = new MetadataProperty[metadata.PropertyDefinitions.Count + 1];
this.eventDefs = new MetadataEvent[metadata.EventDefinitions.Count + 1];
}
}
internal string GetString(StringHandle name)
@ -156,14 +158,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -156,14 +158,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
public IEnumerable<ITypeDefinition> TypeDefinitions {
get {
for (int row = 1; row < typeDefs.Length; row++) {
var typeDef = LazyInit.VolatileRead(ref typeDefs[row]);
if (typeDef != null) {
yield return typeDef;
} else {
typeDef = new MetadataTypeDefinition(this, MetadataTokens.TypeDefinitionHandle(row));
yield return LazyInit.GetOrSet(ref typeDefs[row], typeDef);
}
foreach (var tdHandle in metadata.TypeDefinitions) {
yield return GetDefinition(tdHandle);
}
}
}
@ -172,6 +168,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -172,6 +168,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
if (handle.IsNil)
return null;
if (typeDefs == null)
return new MetadataTypeDefinition(this, handle);
int row = MetadataTokens.GetRowNumber(handle);
if (row >= typeDefs.Length)
HandleOutOfRange(handle);
@ -186,6 +184,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -186,6 +184,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
if (handle.IsNil)
return null;
if (fieldDefs == null)
return new MetadataField(this, handle);
int row = MetadataTokens.GetRowNumber(handle);
if (row >= fieldDefs.Length)
HandleOutOfRange(handle);
@ -200,6 +200,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -200,6 +200,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
if (handle.IsNil)
return null;
if (methodDefs == null)
return new MetadataMethod(this, handle);
int row = MetadataTokens.GetRowNumber(handle);
Debug.Assert(row != 0);
if (row >= methodDefs.Length)
@ -215,6 +217,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -215,6 +217,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
if (handle.IsNil)
return null;
if (propertyDefs == null)
return new MetadataProperty(this, handle);
int row = MetadataTokens.GetRowNumber(handle);
Debug.Assert(row != 0);
if (row >= methodDefs.Length)
@ -230,6 +234,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -230,6 +234,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
if (handle.IsNil)
return null;
if (eventDefs == null)
return new MetadataEvent(this, handle);
int row = MetadataTokens.GetRowNumber(handle);
Debug.Assert(row != 0);
if (row >= methodDefs.Length)

7
ILSpy/LoadedAssembly.cs

@ -99,6 +99,9 @@ namespace ICSharpCode.ILSpy @@ -99,6 +99,9 @@ namespace ICSharpCode.ILSpy
/// Gets a type system containing all types from this assembly + primitve types from mscorlib.
/// Returns null in case of load errors.
/// </summary>
/// <remarks>
/// This is an uncached type system.
/// </remarks>
public ICompilation GetTypeSystemOrNull()
{
if (typeSystem != null)
@ -106,7 +109,9 @@ namespace ICSharpCode.ILSpy @@ -106,7 +109,9 @@ namespace ICSharpCode.ILSpy
var module = GetPEFileOrNull();
if (module == null)
return null;
return typeSystem = new SimpleCompilation(module, MinimalCorlib.Instance);
return typeSystem = new SimpleCompilation(
module.WithOptions(TypeSystemOptions.Default | TypeSystemOptions.Uncached),
MinimalCorlib.Instance);
}
public AssemblyList AssemblyList => assemblyList;

3
ILSpy/MainWindow.xaml.cs

@ -637,7 +637,8 @@ namespace ICSharpCode.ILSpy @@ -637,7 +637,8 @@ namespace ICSharpCode.ILSpy
OpenLink(opCode.Link);
break;
case ValueTuple<PEFile, System.Reflection.Metadata.EntityHandle> unresolvedEntity:
var typeSystem = new DecompilerTypeSystem(unresolvedEntity.Item1, unresolvedEntity.Item1.GetAssemblyResolver());
var typeSystem = new DecompilerTypeSystem(unresolvedEntity.Item1, unresolvedEntity.Item1.GetAssemblyResolver(),
TypeSystemOptions.Default | TypeSystemOptions.Uncached);
reference = typeSystem.MainModule.ResolveEntity(unresolvedEntity.Item2);
goto default;
default:

2
ILSpy/TextView/DecompilerTextView.cs

@ -210,7 +210,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -210,7 +210,7 @@ namespace ICSharpCode.ILSpy.TextView
} else if (segment.Reference is IEntity entity) {
return CreateTextBlockForEntity(entity);
} else if (segment.Reference is ValueTuple<PEFile, System.Reflection.Metadata.EntityHandle> unresolvedEntity) {
var typeSystem = new DecompilerTypeSystem(unresolvedEntity.Item1, unresolvedEntity.Item1.GetAssemblyResolver());
var typeSystem = new DecompilerTypeSystem(unresolvedEntity.Item1, unresolvedEntity.Item1.GetAssemblyResolver(), TypeSystemOptions.Default | TypeSystemOptions.Uncached);
IEntity resolved = typeSystem.MainModule.ResolveEntity(unresolvedEntity.Item2);
if (resolved == null)
return null;

3
ILSpy/TreeNodes/BaseTypesEntryNode.cs

@ -49,7 +49,8 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -49,7 +49,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
ITypeDefinition TryResolve(PEFile module, EntityHandle handle, IType type, bool mayRetry = true)
{
DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver());
DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver(),
TypeSystemOptions.Default | TypeSystemOptions.Uncached);
var t = typeSystem.MainModule.ResolveEntity(handle) as ITypeDefinition;
if (t != null) {
showExpander = t.DirectBaseTypes.Any();

Loading…
Cancel
Save