Browse Source

#1203, #2092: New logic for resolving assembly references within the type system.

We now avoid the old `IModuleReference` interface which required allocating for every type being resolved.
Instead `MetadataModule.ResolveModule` now combines decoding+resolving assembly references into a single step.
This allows the type system to maintain a cache indexed by row number.

This also changes the behavior of resolving references within a compilation: We now prefer an exact match (name + version + publickeytoken) first; and fall back to a name-only match only if no exact match exists.
This somewhat improves the decompilation of assemblies created by using ilmerge to combine assemblies with different target frameworks.
pull/2113/head
Daniel Grunwald 5 years ago
parent
commit
8061634e67
  1. 1
      ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs
  2. 60
      ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs
  3. 3
      ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs
  4. 19
      ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

1
ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs

@ -147,6 +147,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -147,6 +147,7 @@ namespace ICSharpCode.Decompiler.Metadata
return Disassembler.DisassemblerHelpers.Escape(name);
}
[Obsolete("Use MetadataModule.GetDeclaringModule() instead")]
public static IModuleReference GetDeclaringModule(this TypeReferenceHandle handle, MetadataReader reader)
{
var tr = reader.GetTypeReference(handle);

60
ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs

@ -48,6 +48,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -48,6 +48,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
readonly MetadataMethod[] methodDefs;
readonly MetadataProperty[] propertyDefs;
readonly MetadataEvent[] eventDefs;
readonly IModule[] referencedAssemblies;
internal MetadataModule(ICompilation compilation, Metadata.PEFile peFile, TypeSystemOptions options)
{
@ -79,6 +80,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -79,6 +80,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
this.methodDefs = new MetadataMethod[metadata.MethodDefinitions.Count + 1];
this.propertyDefs = new MetadataProperty[metadata.PropertyDefinitions.Count + 1];
this.eventDefs = new MetadataEvent[metadata.EventDefinitions.Count + 1];
this.referencedAssemblies = new IModule[metadata.AssemblyReferences.Count + 1];
}
}
@ -270,6 +272,64 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -270,6 +272,64 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
#endregion
#region Resolve Module
public IModule ResolveModule(AssemblyReferenceHandle handle)
{
if (handle.IsNil)
return null;
if (referencedAssemblies == null)
return ResolveModuleUncached(handle);
int row = MetadataTokens.GetRowNumber(handle);
Debug.Assert(row != 0);
if (row >= referencedAssemblies.Length)
HandleOutOfRange(handle);
var module = LazyInit.VolatileRead(ref referencedAssemblies[row]);
if (module != null)
return module;
module = ResolveModuleUncached(handle);
return LazyInit.GetOrSet(ref referencedAssemblies[row], module);
}
IModule ResolveModuleUncached(AssemblyReferenceHandle handle)
{
var asmRef = new Metadata.AssemblyReference(metadata, handle);
return Compilation.FindModuleByReference(asmRef);
}
public IModule ResolveModule(ModuleReferenceHandle handle)
{
if (handle.IsNil)
return null;
var modRef = metadata.GetModuleReference(handle);
string name = metadata.GetString(modRef.Name);
foreach (var mod in Compilation.Modules) {
if (mod.Name == name) {
return mod;
}
}
return null;
}
public IModule GetDeclaringModule(TypeReferenceHandle handle)
{
if (handle.IsNil)
return null;
var tr = metadata.GetTypeReference(handle);
switch (tr.ResolutionScope.Kind) {
case HandleKind.TypeReference:
return GetDeclaringModule((TypeReferenceHandle)tr.ResolutionScope);
case HandleKind.AssemblyReference:
return ResolveModule((AssemblyReferenceHandle)tr.ResolutionScope);
case HandleKind.ModuleReference:
return ResolveModule((ModuleReferenceHandle)tr.ResolutionScope);
default:
return this;
}
}
#endregion
#region Resolve Type
public IType ResolveType(EntityHandle typeRefDefSpec, GenericContext context, CustomAttributeHandleCollection? typeAttributes = null, Nullability nullableContext = Nullability.Oblivious)
{

3
ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs

@ -131,8 +131,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -131,8 +131,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
public IType GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeReferenceHandle handle, byte rawTypeKind)
{
IModuleReference moduleReference = handle.GetDeclaringModule(reader);
IModule resolvedModule = moduleReference.Resolve(module != null ? new SimpleTypeResolveContext(module) : new SimpleTypeResolveContext(compilation));
IModule resolvedModule = module.GetDeclaringModule(handle);
var fullTypeName = handle.GetFullTypeName(reader);
IType type;
if (resolvedModule != null) {

19
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -292,7 +292,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -292,7 +292,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// Gets all type definitions in the compilation.
/// This may include types from referenced assemblies that are not accessible in the main assembly.
/// </summary>
public static IEnumerable<ITypeDefinition> GetAllTypeDefinitions (this ICompilation compilation)
public static IEnumerable<ITypeDefinition> GetAllTypeDefinitions(this ICompilation compilation)
{
return compilation.Modules.SelectMany(a => a.TypeDefinitions);
}
@ -301,7 +301,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -301,7 +301,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// Gets all top level type definitions in the compilation.
/// This may include types from referenced assemblies that are not accessible in the main assembly.
/// </summary>
public static IEnumerable<ITypeDefinition> GetTopLevelTypeDefinitions (this ICompilation compilation)
public static IEnumerable<ITypeDefinition> GetTopLevelTypeDefinitions(this ICompilation compilation)
{
return compilation.Modules.SelectMany(a => a.TopLevelTypeDefinitions);
}
@ -390,7 +390,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -390,7 +390,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// (if the given <paramref name="entity"/> in an <c>override</c>)
/// should be returned.
/// </param>
public static bool HasAttribute(this IEntity entity, KnownAttribute attributeType, bool inherit=false)
public static bool HasAttribute(this IEntity entity, KnownAttribute attributeType, bool inherit = false)
{
return GetAttribute(entity, attributeType, inherit) != null;
}
@ -410,7 +410,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -410,7 +410,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// If inherit is true, an from the entity itself will be returned if possible;
/// and the base entity will only be searched if none exists.
/// </returns>
public static IAttribute GetAttribute(this IEntity entity, KnownAttribute attributeType, bool inherit=false)
public static IAttribute GetAttribute(this IEntity entity, KnownAttribute attributeType, bool inherit = false)
{
return GetAttributes(entity, inherit).FirstOrDefault(a => a.AttributeType.IsKnownType(attributeType));
}
@ -478,8 +478,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -478,8 +478,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
public static ITypeDefinition GetTypeDefinition(this IModule module, string namespaceName, string name, int typeParameterCount = 0)
{
if (module == null)
throw new ArgumentNullException ("assembly");
return module.GetTypeDefinition (new TopLevelTypeName (namespaceName, name, typeParameterCount));
throw new ArgumentNullException("assembly");
return module.GetTypeDefinition(new TopLevelTypeName(namespaceName, name, typeParameterCount));
}
#endregion
@ -560,7 +560,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -560,7 +560,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
public static IModule FindModuleByReference(this ICompilation compilation, IAssemblyReference assemblyName)
{
foreach (var module in compilation.Modules) {
if (module.FullAssemblyName == assemblyName.FullName) {
if (string.Equals(module.FullAssemblyName, assemblyName.FullName, StringComparison.OrdinalIgnoreCase)) {
return module;
}
}
foreach (var module in compilation.Modules) {
if (string.Equals(module.Name, assemblyName.Name, StringComparison.OrdinalIgnoreCase)) {
return module;
}
}

Loading…
Cancel
Save