More R2RDump refactoring to make it easier for ILSpy to consume the APIs (#1209)
authorAndrew Au <andrewau@microsoft.com>
Sun, 29 Dec 2019 21:51:46 +0000 (13:51 -0800)
committerGitHub <noreply@github.com>
Sun, 29 Dec 2019 21:51:46 +0000 (13:51 -0800)
src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/IAssemblyResolver.cs
src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/R2RReader.cs
src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/R2RSignature.cs
src/coreclr/src/tools/r2rdump/R2RDump.cs
src/coreclr/src/tools/r2rdump/TextDumper.cs

index b58344c..1b859c2 100644 (file)
@@ -1,12 +1,14 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Reflection.Metadata;
 
 namespace ILCompiler.Reflection.ReadyToRun
 {
     public interface IAssemblyResolver
     {
-        string FindAssembly(string name, string filename);
+        MetadataReader FindAssembly(MetadataReader metadataReader, AssemblyReferenceHandle assemblyReferenceHandle, string parentFile);
         // TODO (refactoring) - signature formatting options should be independent of assembly resolver
         bool Naked { get; }
         bool SignatureBinary { get; }
index c3704d9..6e89eec 100644 (file)
@@ -77,142 +77,57 @@ namespace ILCompiler.Reflection.ReadyToRun
         }
     }
 
-    public class EcmaMetadataReader
+    public sealed class R2RReader
     {
-        protected IAssemblyResolver _assemblyResolver;
-        protected Dictionary<string, EcmaMetadataReader> _assemblyCache;
-
+        private IAssemblyResolver _assemblyResolver;
+        private Dictionary<int, MetadataReader> _assemblyCache;
+        private Dictionary<int, DebugInfo> _runtimeFunctionToDebugInfo;
+        private MetadataReader _manifestReader;
+        private List<AssemblyReferenceHandle> _manifestReferences;
 
         /// <summary>
         /// Underlying PE image reader is used to access raw PE structures like header
         /// or section list.
         /// </summary>
-        public readonly PEReader PEReader;
+        public PEReader PEReader { get; private set; }
 
         /// <summary>
         /// MetadataReader is used to access the MSIL metadata in the R2R file.
         /// </summary>
-        public readonly MetadataReader MetadataReader;
-
-        /// <summary>
-        /// Extra reference assemblies parsed from the manifest metadata.
-        /// Only used by R2R assemblies with larger version bubble.
-        /// The manifest contains extra assembly references created by resolved
-        /// inlines and facades (non-existent in the source MSIL).
-        /// In module overrides, these assembly references are represented
-        /// by indices larger than the number of AssemblyRef rows in MetadataReader.
-        /// The list originates in the top-level R2R image and is copied
-        /// to all reference assemblies for the sake of simplicity.
-        /// </summary>
-        public readonly List<string> ManifestReferenceAssemblies;
+        public MetadataReader MetadataReader { get; private set; }
 
         /// <summary>
         /// Byte array containing the ReadyToRun image
         /// </summary>
-        public byte[] Image { get; }
+        public byte[] Image { get; private set; }
 
         /// <summary>
         /// Name of the image file
         /// </summary>
-        public string Filename { get; set; }
+        public string Filename { get; private set; }
 
         /// <summary>
-        /// The default constructor initializes an empty metadata reader.
-        /// </summary>
-        public EcmaMetadataReader()
-        {
-        }
-
-        public EcmaMetadataReader(IAssemblyResolver assemblyResolver, MetadataReader metadata, PEReader peReader, string filename, List<string> manifestReferenceAssemblies)
-        {
-            _assemblyResolver = assemblyResolver;
-            _assemblyCache = new Dictionary<string, EcmaMetadataReader>();
-            MetadataReader = metadata;
-            PEReader = peReader;
-            ImmutableArray<byte> content = peReader.GetEntireImage().GetContent();
-            // TODO: Avoid copying
-            Image = new byte[content.Length];
-            content.CopyTo(Image);
-            Filename = filename;
-            ManifestReferenceAssemblies = manifestReferenceAssemblies;
-        }
-
-        /// <summary>
-        /// Open an MSIL binary and locate the metadata blob.
+        /// Extra reference assemblies parsed from the manifest metadata.
+        /// Only used by R2R assemblies with larger version bubble.
+        /// The manifest contains extra assembly references created by resolved
+        /// inlines and facades (non-existent in the source MSIL).
+        /// In module overrides, these assembly references are represented
+        /// by indices larger than the number of AssemblyRef rows in MetadataReader.
+        /// The list originates in the top-level R2R image and is copied
+        /// to all reference assemblies for the sake of simplicity.
         /// </summary>
-        /// <param name="options">Ambient options to use</param>
-        /// <param name="filename">PE image</param>
-        /// <param name="manifestReferenceAssemblies">List of reference assemblies from the R2R metadata manifest</param>
-        /// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception>
-        public unsafe EcmaMetadataReader(IAssemblyResolver assemblyResolver, string filename, List<string> manifestReferenceAssemblies)
+        public IEnumerable<string> ManifestReferenceAssemblies
         {
-            _assemblyResolver = assemblyResolver;
-            _assemblyCache = new Dictionary<string, EcmaMetadataReader>();
-            Filename = filename;
-            ManifestReferenceAssemblies = manifestReferenceAssemblies;
-            Image = File.ReadAllBytes(filename);
-
-            fixed (byte* p = Image)
+            get
             {
-                IntPtr ptr = (IntPtr)p;
-                PEReader = new PEReader(p, Image.Length);
-
-                if (!PEReader.HasMetadata)
+                foreach (AssemblyReferenceHandle _manifestReference in _manifestReferences)
                 {
-                    throw new Exception($"ECMA metadata not found in file '{filename}'");
+                    yield return _manifestReader.GetString(_manifestReader.GetAssemblyReference(_manifestReference).Name);
                 }
-
-                MetadataReader = PEReader.GetMetadataReader();
             }
         }
 
         /// <summary>
-        /// Open a given reference assembly (relative to this ECMA metadata file).
-        /// </summary>
-        /// <param name="refAsmIndex">Reference assembly index</param>
-        /// <returns>EcmaMetadataReader instance representing the reference assembly</returns>
-        public EcmaMetadataReader OpenReferenceAssembly(int refAsmIndex)
-        {
-            if (refAsmIndex == 0)
-            {
-                return this;
-            }
-
-            int assemblyRefCount = MetadataReader.GetTableRowCount(TableIndex.AssemblyRef);
-            string name;
-            if (refAsmIndex <= assemblyRefCount)
-            {
-                AssemblyReference asmRef = MetadataReader.GetAssemblyReference(MetadataTokens.AssemblyReferenceHandle(refAsmIndex));
-                name = MetadataReader.GetString(asmRef.Name);
-            }
-            else
-            {
-                name = ManifestReferenceAssemblies[refAsmIndex - assemblyRefCount - 2];
-            }
-
-            EcmaMetadataReader ecmaReader;
-            if (!_assemblyCache.TryGetValue(name, out ecmaReader))
-            {
-                string assemblyPath = _assemblyResolver.FindAssembly(name, Filename);
-                if (assemblyPath == null)
-                {
-                    throw new Exception($"Missing reference assembly: {name}");
-                }
-                ecmaReader = new EcmaMetadataReader(_assemblyResolver, assemblyPath, ManifestReferenceAssemblies);
-                _assemblyCache.Add(name, ecmaReader);
-            }
-            return ecmaReader;
-        }
-    }
-
-    public class R2RReader : EcmaMetadataReader
-    {
-        /// <summary>
-        /// True if the image is ReadyToRun
-        /// </summary>
-        public bool IsR2R { get; set; }
-
-        /// <summary>
         /// The type of target machine
         /// </summary>
         public Machine Machine { get; set; }
@@ -278,18 +193,17 @@ namespace ILCompiler.Reflection.ReadyToRun
         /// </summary>
         public Dictionary<int, string> ImportCellNames { get; private set; }
 
-        private Dictionary<int, DebugInfo> _runtimeFunctionToDebugInfo = new Dictionary<int, DebugInfo>();
-
-        public R2RReader() { }
-
         /// <summary>
         /// Initializes the fields of the R2RHeader and R2RMethods
         /// </summary>
         /// <param name="filename">PE image</param>
         /// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception>
         public R2RReader(IAssemblyResolver assemblyResolver, MetadataReader metadata, PEReader peReader, string filename)
-            : base(assemblyResolver, metadata, peReader, filename, new List<string>())
         {
+            _assemblyResolver = assemblyResolver;
+            MetadataReader = metadata;
+            PEReader = peReader;            
+            Filename = filename;
             Initialize();
         }
 
@@ -298,16 +212,99 @@ namespace ILCompiler.Reflection.ReadyToRun
         /// </summary>
         /// <param name="filename">PE image</param>
         /// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception>
-        public R2RReader(IAssemblyResolver assemblyResolver, string filename)
-            : base(assemblyResolver, filename, new List<string>())
+        public unsafe R2RReader(IAssemblyResolver assemblyResolver, string filename)
         {
+            _assemblyResolver = assemblyResolver;
+            Filename = filename;
             Initialize();
         }
 
         private unsafe void Initialize()
         {
-            IsR2R = ((PEReader.PEHeaders.CorHeader.Flags & CorFlags.ILLibrary) != 0);
-            if (!IsR2R)
+            _assemblyCache = new Dictionary<int, MetadataReader>();
+            this._manifestReferences = new List<AssemblyReferenceHandle>();
+
+            if (MetadataReader == null)
+            {
+                Image = File.ReadAllBytes(Filename);
+
+                fixed (byte* p = Image)
+                {
+                    IntPtr ptr = (IntPtr)p;
+                    PEReader = new PEReader(p, Image.Length);
+
+                    if (!PEReader.HasMetadata)
+                    {
+                        throw new Exception($"ECMA metadata not found in file '{Filename}'");
+                    }
+
+                    MetadataReader = PEReader.GetMetadataReader();
+                }
+            }
+            else
+            {
+                ImmutableArray<byte> content = PEReader.GetEntireImage().GetContent();
+                // TODO: Avoid copying
+                Image = new byte[content.Length];
+                content.CopyTo(Image);
+            }
+
+            ParseHeader();
+
+            ParseDebugInfo();
+
+            if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA))
+            {
+                R2RSection manifestMetadata = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA];
+                fixed (byte* image = Image)
+                {
+                    _manifestReader = new MetadataReader(image + GetOffset(manifestMetadata.RelativeVirtualAddress), manifestMetadata.Size);
+                    int assemblyRefCount = _manifestReader.GetTableRowCount(TableIndex.AssemblyRef);
+                    for (int assemblyRefIndex = 1; assemblyRefIndex <= assemblyRefCount; assemblyRefIndex++)
+                    {
+                        AssemblyReferenceHandle asmRefHandle = MetadataTokens.AssemblyReferenceHandle(assemblyRefIndex);
+                        _manifestReferences.Add(asmRefHandle);
+                    }
+                }
+            }
+
+            if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO))
+            {
+                R2RSection exceptionInfoSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO];
+                EHLookupTable = new EHLookupTable(Image, GetOffset(exceptionInfoSection.RelativeVirtualAddress), exceptionInfoSection.Size);
+            }
+
+            ImportSections = new List<R2RImportSection>();
+            ImportCellNames = new Dictionary<int, string>();
+            ParseImportSections();
+
+            R2RMethods = new List<R2RMethod>();
+            InstanceMethods = new List<InstanceMethod>();
+
+            if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS))
+            {
+                int runtimeFunctionSize = CalculateRuntimeFunctionSize();
+                R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS];
+
+                uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize);
+                int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress);
+                bool[] isEntryPoint = new bool[nRuntimeFunctions];
+
+                // initialize R2RMethods
+                ParseMethodDefEntrypoints(isEntryPoint);
+                ParseInstanceMethodEntrypoints(isEntryPoint);
+                ParseRuntimeFunctions(isEntryPoint, runtimeFunctionOffset, runtimeFunctionSize);
+            }
+
+            AvailableTypes = new List<string>();
+            ParseAvailableTypes();
+
+            CompilerIdentifier = ParseCompilerIdentifier();
+        }
+
+        private unsafe void ParseHeader()
+        {
+            if ((PEReader.PEHeaders.CorHeader.Flags & CorFlags.ILLibrary) == 0)
             {
                 throw new BadImageFormatException("The file is not a ReadyToRun image");
             }
@@ -367,58 +364,6 @@ namespace ILCompiler.Reflection.ReadyToRun
             {
                 throw new BadImageFormatException("The calculated size of the R2RHeader doesn't match the size saved in the ManagedNativeHeaderDirectory");
             }
-
-            ParseDebugInfo();
-
-            if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA))
-            {
-                R2RSection manifestMetadata = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA];
-                fixed (byte* image = Image)
-                {
-                    MetadataReader manifestReader = new MetadataReader(image + GetOffset(manifestMetadata.RelativeVirtualAddress), manifestMetadata.Size);
-                    int assemblyRefCount = manifestReader.GetTableRowCount(TableIndex.AssemblyRef);
-                    for (int assemblyRefIndex = 1; assemblyRefIndex <= assemblyRefCount; assemblyRefIndex++)
-                    {
-                        AssemblyReferenceHandle asmRefHandle = MetadataTokens.AssemblyReferenceHandle(assemblyRefIndex);
-                        AssemblyReference asmRef = manifestReader.GetAssemblyReference(asmRefHandle);
-                        string asmRefName = manifestReader.GetString(asmRef.Name);
-                        ManifestReferenceAssemblies.Add(asmRefName);
-                    }
-                }
-            }
-
-            if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO))
-            {
-                R2RSection exceptionInfoSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO];
-                EHLookupTable = new EHLookupTable(Image, GetOffset(exceptionInfoSection.RelativeVirtualAddress), exceptionInfoSection.Size);
-            }
-
-            ImportSections = new List<R2RImportSection>();
-            ImportCellNames = new Dictionary<int, string>();
-            ParseImportSections();
-
-            R2RMethods = new List<R2RMethod>();
-            InstanceMethods = new List<InstanceMethod>();
-
-            if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS))
-            {
-                int runtimeFunctionSize = CalculateRuntimeFunctionSize();
-                R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS];
-
-                uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize);
-                int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress);
-                bool[] isEntryPoint = new bool[nRuntimeFunctions];
-
-                // initialize R2RMethods
-                ParseMethodDefEntrypoints(isEntryPoint);
-                ParseInstanceMethodEntrypoints(isEntryPoint);
-                ParseRuntimeFunctions(isEntryPoint, runtimeFunctionOffset, runtimeFunctionSize);
-            }
-
-            AvailableTypes = new List<string>();
-            ParseAvailableTypes();
-
-            CompilerIdentifier = ParseCompilerIdentifier();
         }
 
         public bool InputArchitectureSupported()
@@ -784,6 +729,7 @@ namespace ILCompiler.Reflection.ReadyToRun
 
         private void ParseDebugInfo()
         {
+            _runtimeFunctionToDebugInfo = new Dictionary<int, DebugInfo>();
             if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_DEBUG_INFO))
             {
                 return;
@@ -824,7 +770,7 @@ namespace ILCompiler.Reflection.ReadyToRun
         /// <summary>
         /// Get the full name of an ExportedType, including namespace
         /// </summary>
-        public static string GetExportedTypeFullName(MetadataReader mdReader, ExportedTypeHandle handle)
+        private static string GetExportedTypeFullName(MetadataReader mdReader, ExportedTypeHandle handle)
         {
             string typeNamespace = "";
             string typeStr = "";
@@ -912,5 +858,46 @@ namespace ILCompiler.Reflection.ReadyToRun
 
             return cells.ToArray();
         }
+
+        /// <summary>
+        /// Open a given reference assembly (relative to this ECMA metadata file).
+        /// </summary>
+        /// <param name="refAsmIndex">Reference assembly index</param>
+        /// <returns>MetadataReader instance representing the reference assembly</returns>
+        internal MetadataReader OpenReferenceAssembly(int refAsmIndex)
+        {
+            if (refAsmIndex == 0)
+            {
+                return this.MetadataReader;
+            }
+
+            int assemblyRefCount = MetadataReader.GetTableRowCount(TableIndex.AssemblyRef);
+            MetadataReader metadataReader;
+            AssemblyReferenceHandle assemblyReferenceHandle;
+            if (refAsmIndex <= assemblyRefCount)
+            {
+                metadataReader = MetadataReader;
+                assemblyReferenceHandle = MetadataTokens.AssemblyReferenceHandle(refAsmIndex);
+            }
+            else
+            {
+                metadataReader = _manifestReader;
+                assemblyReferenceHandle = _manifestReferences[refAsmIndex - assemblyRefCount - 2];
+            }
+            
+
+            MetadataReader result;
+            if (!_assemblyCache.TryGetValue(refAsmIndex, out result))
+            {
+                result = _assemblyResolver.FindAssembly(metadataReader, assemblyReferenceHandle, Filename);
+                if (result == null)
+                {
+                    string name = metadataReader.GetString(metadataReader.GetAssemblyReference(assemblyReferenceHandle).Name);
+                    throw new Exception($"Missing reference assembly: {name}");
+                }
+                _assemblyCache.Add(refAsmIndex, result);
+            }
+            return result;
+        }
     }
 }
index 40a2bd3..87c0361 100644 (file)
@@ -39,9 +39,9 @@ namespace ILCompiler.Reflection.ReadyToRun
             return formatter.EmitHandleName(handle, namespaceQualified, owningTypeOverride, signaturePrefix);
         }
 
-        public static string FormatSignature(IAssemblyResolver assemblyResolver, EcmaMetadataReader ecmaReader, int imageOffset)
+        public static string FormatSignature(IAssemblyResolver assemblyResolver, R2RReader r2rReader, int imageOffset)
         {
-            SignatureDecoder decoder = new SignatureDecoder(assemblyResolver, ecmaReader, imageOffset);
+            SignatureDecoder decoder = new SignatureDecoder(assemblyResolver, r2rReader, imageOffset);
             string result = decoder.ReadR2RSignature();
             return result;
         }
@@ -348,12 +348,12 @@ namespace ILCompiler.Reflection.ReadyToRun
         /// <summary>
         /// ECMA reader is used to access the embedded MSIL metadata blob in the R2R file.
         /// </summary>
-        private readonly EcmaMetadataReader _ecmaReader;
+        private readonly MetadataReader _metadataReader;
 
         /// <summary>
         /// ECMA reader representing the top-level signature context.
         /// </summary>
-        private readonly EcmaMetadataReader _contextReader;
+        private readonly R2RReader _contextReader;
 
         /// <summary>
         /// Dump options are used to specify details of signature formatting.
@@ -379,28 +379,28 @@ namespace ILCompiler.Reflection.ReadyToRun
         /// Construct the signature decoder by storing the image byte array and offset within the array.
         /// </summary>
         /// <param name="options">Dump options and paths</param>
-        /// <param name="ecmaReader">EcmaMetadataReader object representing the PE file containing the ECMA metadata</param>
+        /// <param name="r2rReader">R2RReader object representing the PE file containing the ECMA metadata</param>
         /// <param name="offset">Signature offset within the PE file byte array</param>
-        public SignatureDecoder(IAssemblyResolver options, EcmaMetadataReader ecmaReader, int offset)
+        public SignatureDecoder(IAssemblyResolver options, R2RReader r2rReader, int offset)
         {
-            _ecmaReader = ecmaReader;
+            _metadataReader = r2rReader.MetadataReader;
             _options = options;
-            _image = ecmaReader.Image;
+            _image = r2rReader.Image;
             _offset = offset;
-            _contextReader = ecmaReader;
+            _contextReader = r2rReader;
         }
 
         /// <summary>
         /// Construct the signature decoder by storing the image byte array and offset within the array.
         /// </summary>
         /// <param name="options">Dump options and paths</param>
-        /// <param name="ecmaReader">Metadata reader for the R2R image</param>
+        /// <param name="metadataReader">Metadata reader for the R2R image</param>
         /// <param name="signature">Signature to parse</param>
         /// <param name="offset">Signature offset within the signature byte array</param>
         /// <param name="contextReader">Top-level signature context reader</param>
-        public SignatureDecoder(IAssemblyResolver options, EcmaMetadataReader ecmaReader, byte[] signature, int offset, EcmaMetadataReader contextReader)
+        private SignatureDecoder(IAssemblyResolver options, MetadataReader metadataReader, byte[] signature, int offset, R2RReader contextReader)
         {
-            _ecmaReader = ecmaReader;
+            _metadataReader = metadataReader;
             _options = options;
             _image = signature;
             _offset = offset;
@@ -638,7 +638,7 @@ namespace ILCompiler.Reflection.ReadyToRun
             {
                 fixupType &= ~(uint)ReadyToRunFixupKind.ModuleOverride;
                 int moduleIndex = (int)ReadUIntAndEmitInlineSignatureBinary(builder);
-                EcmaMetadataReader refAsmEcmaReader = _contextReader.OpenReferenceAssembly(moduleIndex);
+                MetadataReader refAsmEcmaReader = _contextReader.OpenReferenceAssembly(moduleIndex);
                 moduleDecoder = new SignatureDecoder(_options, refAsmEcmaReader, _image, _offset, _contextReader);
             }
 
@@ -1069,7 +1069,7 @@ namespace ILCompiler.Reflection.ReadyToRun
                 case CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG:
                     {
                         int moduleIndex = (int)ReadUIntAndEmitInlineSignatureBinary(builder);
-                        EcmaMetadataReader refAsmReader = _contextReader.OpenReferenceAssembly(moduleIndex);
+                        MetadataReader refAsmReader = _contextReader.OpenReferenceAssembly(moduleIndex);
                         SignatureDecoder refAsmDecoder = new SignatureDecoder(_options, refAsmReader, _image, _offset, _contextReader);
                         refAsmDecoder.ParseType(builder);
                         _offset = refAsmDecoder.Offset;
@@ -1089,11 +1089,11 @@ namespace ILCompiler.Reflection.ReadyToRun
 
                 ReadElementType();
                 int moduleIndex = (int)ReadUInt();
-                EcmaMetadataReader refAsmReader = _contextReader.OpenReferenceAssembly(moduleIndex);
+                MetadataReader refAsmReader = _contextReader.OpenReferenceAssembly(moduleIndex);
 
                 _offset = currentOffset;
 
-                return refAsmReader.MetadataReader;
+                return refAsmReader;
             }
             return null;
         }
@@ -1119,7 +1119,7 @@ namespace ILCompiler.Reflection.ReadyToRun
             StringBuilder signaturePrefixBuilder = new StringBuilder();
             uint token = ReadTokenAndEmitInlineSignatureBinary(signaturePrefixBuilder);
             builder.Append(MetadataNameFormatter.FormatHandle(
-                _ecmaReader.MetadataReader,
+                _metadataReader,
                 MetadataTokens.Handle((int)token),
                 owningTypeOverride: null,
                 signaturePrefix: signaturePrefixBuilder.ToString()));
@@ -1145,7 +1145,7 @@ namespace ILCompiler.Reflection.ReadyToRun
             string owningTypeOverride = null;
             if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0)
             {
-                SignatureDecoder owningTypeDecoder = new SignatureDecoder(_options, _ecmaReader, _image, _offset, _contextReader);
+                SignatureDecoder owningTypeDecoder = new SignatureDecoder(_options, _metadataReader, _image, _offset, _contextReader);
                 owningTypeOverride = owningTypeDecoder.ReadTypeSignatureNoEmit();
                 _offset = owningTypeDecoder._offset;
             }
@@ -1193,7 +1193,7 @@ namespace ILCompiler.Reflection.ReadyToRun
             StringBuilder signaturePrefixBuilder = new StringBuilder();
             uint methodDefToken = ReadUIntAndEmitInlineSignatureBinary(signaturePrefixBuilder) | (uint)CorTokenType.mdtMethodDef;
             builder.Append(MetadataNameFormatter.FormatHandle(
-                _ecmaReader.MetadataReader,
+                _metadataReader,
                 MetadataTokens.Handle((int)methodDefToken),
                 namespaceQualified: true,
                 owningTypeOverride: owningTypeOverride,
@@ -1210,7 +1210,7 @@ namespace ILCompiler.Reflection.ReadyToRun
             StringBuilder signaturePrefixBuilder = new StringBuilder();
             uint methodRefToken = ReadUIntAndEmitInlineSignatureBinary(signaturePrefixBuilder) | (uint)CorTokenType.mdtMemberRef;
             builder.Append(MetadataNameFormatter.FormatHandle(
-                _ecmaReader.MetadataReader,
+                _metadataReader,
                 MetadataTokens.Handle((int)methodRefToken),
                 namespaceQualified: false,
                 owningTypeOverride: owningTypeOverride,
@@ -1242,7 +1242,7 @@ namespace ILCompiler.Reflection.ReadyToRun
                 fieldToken = ReadUIntAndEmitInlineSignatureBinary(signaturePrefixBuilder) | (uint)CorTokenType.mdtFieldDef;
             }
             builder.Append(MetadataNameFormatter.FormatHandle(
-                _ecmaReader.MetadataReader,
+                _metadataReader,
                 MetadataTokens.Handle((int)fieldToken),
                 namespaceQualified: false,
                 owningTypeOverride: owningTypeOverride,
@@ -1640,7 +1640,7 @@ namespace ILCompiler.Reflection.ReadyToRun
         {
             uint rid = ReadUIntAndEmitInlineSignatureBinary(builder);
             UserStringHandle stringHandle = MetadataTokens.UserStringHandle((int)rid);
-            builder.Append(_ecmaReader.MetadataReader.GetUserString(stringHandle));
+            builder.Append(_metadataReader.GetUserString(stringHandle));
         }
     }
 }
index 45ae837..5f8a330 100644 (file)
@@ -9,7 +9,9 @@ using System.CommandLine;
 using System.CommandLine.Invocation;
 using System.IO;
 using System.Linq;
+using System.Reflection.Metadata;
 using System.Reflection.Metadata.Ecma335;
+using System.Reflection.PortableExecutable;
 using System.Text;
 using System.Threading.Tasks;
 
@@ -44,8 +46,6 @@ namespace R2RDump
         public bool SignatureBinary { get; set; }
         public bool InlineSignatureBinary { get; set; }
 
-        public Dictionary<string, EcmaMetadataReader> AssemblyCache = new Dictionary<string, EcmaMetadataReader>(StringComparer.OrdinalIgnoreCase);
-
         /// <summary>
         /// Probing extensions to use when looking up assemblies under reference paths.
         /// </summary>
@@ -58,13 +58,15 @@ namespace R2RDump
         /// <param name="simpleName">Simple name of the assembly to look up</param>
         /// <param name="parentFile">Name of assembly from which we're performing the lookup</param>
         /// <returns></returns>
-        public string FindAssembly(string simpleName, string parentFile)
+
+        public MetadataReader FindAssembly(MetadataReader metadataReader, AssemblyReferenceHandle assemblyReferenceHandle, string parentFile)
         {
+            string simpleName = metadataReader.GetString(metadataReader.GetAssemblyReference(assemblyReferenceHandle).Name);
             foreach (FileInfo refAsm in Reference ?? Enumerable.Empty<FileInfo>())
             {
                 if (Path.GetFileNameWithoutExtension(refAsm.FullName).Equals(simpleName, StringComparison.OrdinalIgnoreCase))
                 {
-                    return refAsm.FullName;
+                    return Open(refAsm.FullName);
                 }
             }
 
@@ -78,13 +80,31 @@ namespace R2RDump
                     string probeFile = Path.Combine(refPath, simpleName + extension);
                     if (File.Exists(probeFile))
                     {
-                        return probeFile;
+                        return Open(probeFile);
                     }
                 }
             }
 
             return null;
         }
+
+        private static unsafe MetadataReader Open(string filename)
+        {
+            byte[] Image = File.ReadAllBytes(filename);
+
+            fixed (byte* p = Image)
+            {
+                IntPtr ptr = (IntPtr)p;
+                PEReader peReader = new PEReader(p, Image.Length);
+
+                if (!peReader.HasMetadata)
+                {
+                    throw new Exception($"ECMA metadata not found in file '{filename}'");
+                }
+
+                return peReader.GetMetadataReader();
+            }
+        }
     }
 
     public abstract class Dumper
index 0784778..4a4e338 100644 (file)
@@ -377,10 +377,12 @@ namespace R2RDump
                         _writer.WriteLine($"[ID 0x{assemblyRefIndex:X2}]: {assemblyRefName}");
                     }
 
-                    _writer.WriteLine($"Manifest metadata AssemblyRef's ({_r2r.ManifestReferenceAssemblies.Count} entries):");
-                    for (int manifestAsmIndex = 0; manifestAsmIndex < _r2r.ManifestReferenceAssemblies.Count; manifestAsmIndex++)
+                    _writer.WriteLine($"Manifest metadata AssemblyRef's ({_r2r.ManifestReferenceAssemblies.Count()} entries):");
+                    int manifestAsmIndex = 0;
+                    foreach (string manifestReferenceAssembly in _r2r.ManifestReferenceAssemblies)
                     {
-                        _writer.WriteLine($"[ID 0x{manifestAsmIndex + assemblyRefCount + 2:X2}]: {_r2r.ManifestReferenceAssemblies[manifestAsmIndex]}");
+                        _writer.WriteLine($"[ID 0x{manifestAsmIndex + assemblyRefCount + 2:X2}]: {manifestReferenceAssembly}");
+                        manifestAsmIndex++;
                     }
                     break;
                 case R2RSection.SectionType.READYTORUN_SECTION_ATTRIBUTEPRESENCE: