Expand PerfMap format to support metadata for symbol indexation (#53792)
authorTomáš Rylek <trylek@microsoft.com>
Thu, 1 Jul 2021 23:17:59 +0000 (01:17 +0200)
committerGitHub <noreply@github.com>
Thu, 1 Jul 2021 23:17:59 +0000 (01:17 +0200)
I have expanded the PerfMap format produced by Crossgen2 and
R2RDump to produce metadata in form of pseudo-symbol records with
high addresses. In this version I have implemented four metadata
entries - output GUID, target OS, target architecture and perfmap
format version number.  I have verified for System.Private.CoreLib
and for the composite framework that Crossgen2 and R2RDump
produce identical metadata.

To facilitate a smooth transition to the new perfmap format, in
accordance with Juan's suggestion I have introduced a new command-line
option to explicitly specify the perfmap format revision. As of today,
0 corresponds to the legacy Crossgen1-style output where the
perfmap file name includes the {MVID} section, perfmap format #1
corresponds to current Crossgen2 with its new naming scheme.
As of today there are no differences in the file content.

Thanks

Tomas

17 files changed:
src/coreclr/tools/aot/ILCompiler.Diagnostics/AssemblyInfo.cs [new file with mode: 0644]
src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj
src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/OutputInfoBuilder.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs
src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj
src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs
src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs
src/coreclr/tools/aot/crossgen2/Program.cs
src/coreclr/tools/aot/crossgen2/Properties/Resources.resx
src/coreclr/tools/r2rdump/CommandLineOptions.cs
src/coreclr/tools/r2rdump/R2RDump.cs
src/coreclr/tools/r2rdump/R2RDump.sln
src/coreclr/tools/r2rdump/TextDumper.cs

diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/AssemblyInfo.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..02ff300
--- /dev/null
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace ILCompiler.Diagnostics
+{
+    public struct AssemblyInfo
+    {
+        public readonly string Name;
+        public readonly Guid Mvid;
+
+        public AssemblyInfo(string name, Guid mvid)
+        {
+            Name = name;
+            Mvid = mvid;
+        }
+    }
+}
index 8c9419d..8fe3bd1 100644 (file)
@@ -17,4 +17,8 @@
     <Configurations>Debug;Release;Checked</Configurations>
   </PropertyGroup>
 
+  <ItemGroup>
+    <ProjectReference Include="..\ILCompiler.TypeSystem.ReadyToRun\ILCompiler.TypeSystem.ReadyToRun.csproj" />
+  </ItemGroup>
+
 </Project>
index 4696bc9..dd494b9 100644 (file)
@@ -4,11 +4,27 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+
+using Internal.TypeSystem;
 
 namespace ILCompiler.Diagnostics
 {
     public class PerfMapWriter
     {
+        public const int LegacyCrossgen1FormatVersion = 0;
+
+        public const int CurrentFormatVersion = 1;
+        
+        public enum PseudoRVA : uint
+        {
+            OutputGuid         = 0xFFFFFFFF,
+            TargetOS           = 0xFFFFFFFE,
+            TargetArchitecture = 0xFFFFFFFD,
+            FormatVersion      = 0xFFFFFFFC,
+        }
+
         private TextWriter _writer;
 
         private PerfMapWriter(TextWriter writer)
@@ -16,11 +32,32 @@ namespace ILCompiler.Diagnostics
             _writer = writer;
         }
 
-        public static void Write(string perfMapFileName, IEnumerable<MethodInfo> methods)
+        public static void Write(string perfMapFileName, int perfMapFormatVersion, IEnumerable<MethodInfo> methods, IEnumerable<AssemblyInfo> inputAssemblies, TargetOS targetOS, TargetArchitecture targetArch)
         {
+            if (perfMapFormatVersion > CurrentFormatVersion)
+            {
+                throw new NotSupportedException(perfMapFormatVersion.ToString());
+            }
+
             using (TextWriter writer = new StreamWriter(perfMapFileName))
             {
+                IEnumerable<AssemblyInfo> orderedInputs = inputAssemblies.OrderBy(asm => asm.Name, StringComparer.OrdinalIgnoreCase);
+
                 PerfMapWriter perfMapWriter = new PerfMapWriter(writer);
+
+                List<byte> inputHash = new List<byte>();
+                foreach (AssemblyInfo inputAssembly in orderedInputs)
+                {
+                    inputHash.AddRange(inputAssembly.Mvid.ToByteArray());
+                }
+                inputHash.Add((byte)targetOS);
+                inputHash.Add((byte)targetArch);
+                Guid outputGuid = new Guid(MD5.HashData(inputHash.ToArray()));
+                perfMapWriter.WriteLine(outputGuid.ToString(), (uint)PseudoRVA.OutputGuid, 0);
+                perfMapWriter.WriteLine(targetOS.ToString(), (uint)PseudoRVA.TargetOS, 0);
+                perfMapWriter.WriteLine(targetArch.ToString(), (uint)PseudoRVA.TargetArchitecture, 0);
+                perfMapWriter.WriteLine(CurrentFormatVersion.ToString(), (uint)PseudoRVA.FormatVersion, 0);
+
                 foreach (MethodInfo methodInfo in methods)
                 {
                     if (methodInfo.HotRVA != 0 && methodInfo.HotLength != 0)
index 74da512..6404f77 100644 (file)
@@ -46,6 +46,12 @@ namespace ILCompiler.DependencyAnalysis
         private readonly EcmaModule _componentModule;
 
         /// <summary>
+        /// Compilation input files. Input files are emitted as perfmap entries and used
+        /// to calculate the output GUID of the ReadyToRun executable for symbol indexation.
+        /// </summary>
+        private readonly IEnumerable<string> _inputFiles;
+
+        /// <summary>
         /// Nodes to emit into the output executable as collected by the dependency analysis.
         /// </summary>
         private readonly IEnumerable<DependencyNode> _nodes;
@@ -101,9 +107,9 @@ namespace ILCompiler.DependencyAnalysis
         private string _perfMapPath;
 
         /// <summary>
-        /// MVID of the input managed module to embed in the perfmap file name.
+        /// Requested version of the perfmap file format
         /// </summary>
-        private Guid? _perfMapMvid;
+        private int _perfMapFormatVersion;
 
         /// <summary>
         /// If non-zero, the PE file will be laid out such that it can naturally be mapped with a higher alignment than 4KB.
@@ -132,6 +138,7 @@ namespace ILCompiler.DependencyAnalysis
         public ReadyToRunObjectWriter(
             string objectFilePath,
             EcmaModule componentModule,
+            IEnumerable<string> inputFiles,
             IEnumerable<DependencyNode> nodes,
             NodeFactory factory,
             bool generateMapFile,
@@ -140,13 +147,14 @@ namespace ILCompiler.DependencyAnalysis
             string pdbPath,
             bool generatePerfMapFile,
             string perfMapPath,
-            Guid? perfMapMvid,
+            int perfMapFormatVersion,
             bool generateProfileFile,
             CallChainProfile callChainProfile,
             int customPESectionAlignment)
         {
             _objectFilePath = objectFilePath;
             _componentModule = componentModule;
+            _inputFiles = inputFiles;
             _nodes = nodes;
             _nodeFactory = factory;
             _customPESectionAlignment = customPESectionAlignment;
@@ -156,7 +164,7 @@ namespace ILCompiler.DependencyAnalysis
             _pdbPath = pdbPath;
             _generatePerfMapFile = generatePerfMapFile;
             _perfMapPath = perfMapPath;
-            _perfMapMvid = perfMapMvid;
+            _perfMapFormatVersion = perfMapFormatVersion;
 
             bool generateMap = (generateMapFile || generateMapCsvFile);
             bool generateSymbols = (generatePdbFile || generatePerfMapFile);
@@ -329,6 +337,11 @@ namespace ILCompiler.DependencyAnalysis
 
                 if (_outputInfoBuilder != null)
                 {
+                    foreach (string inputFile in _inputFiles)
+                    {
+                        _outputInfoBuilder.AddInputModule(_nodeFactory.TypeSystemContext.GetModuleFromPath(inputFile));
+                    }
+
                     r2rPeBuilder.AddSections(_outputInfoBuilder);
 
                     if (_generateMapFile)
@@ -361,7 +374,7 @@ namespace ILCompiler.DependencyAnalysis
                         {
                             path = Path.GetDirectoryName(_objectFilePath);
                         }
-                        _symbolFileBuilder.SavePerfMap(path, _objectFilePath, _perfMapMvid);
+                        _symbolFileBuilder.SavePerfMap(path, _perfMapFormatVersion, _objectFilePath, _nodeFactory.Target.OperatingSystem, _nodeFactory.Target.Architecture);
                     }
 
                     if (_profileFileBuilder != null)
@@ -430,6 +443,7 @@ namespace ILCompiler.DependencyAnalysis
         public static void EmitObject(
             string objectFilePath,
             EcmaModule componentModule,
+            IEnumerable<string> inputFiles,
             IEnumerable<DependencyNode> nodes,
             NodeFactory factory,
             bool generateMapFile,
@@ -438,7 +452,7 @@ namespace ILCompiler.DependencyAnalysis
             string pdbPath,
             bool generatePerfMapFile,
             string perfMapPath,
-            Guid? perfMapMvid,
+            int perfMapFormatVersion,
             bool generateProfileFile,
             CallChainProfile callChainProfile,
             int customPESectionAlignment)
@@ -447,6 +461,7 @@ namespace ILCompiler.DependencyAnalysis
             ReadyToRunObjectWriter objectWriter = new ReadyToRunObjectWriter(
                 objectFilePath,
                 componentModule,
+                inputFiles,
                 nodes,
                 factory,
                 generateMapFile: generateMapFile,
@@ -455,7 +470,7 @@ namespace ILCompiler.DependencyAnalysis
                 pdbPath: pdbPath,
                 generatePerfMapFile: generatePerfMapFile,
                 perfMapPath: perfMapPath,
-                perfMapMvid: perfMapMvid,
+                perfMapFormatVersion: perfMapFormatVersion,
                 generateProfileFile: generateProfileFile,
                 callChainProfile,
                 customPESectionAlignment);
index 1dce9f8..ac7058b 100644 (file)
@@ -247,7 +247,7 @@ namespace ILCompiler
         private readonly string _pdbPath;
         private readonly bool _generatePerfMapFile;
         private readonly string _perfMapPath;
-        private readonly Guid? _perfMapMvid;
+        private readonly int _perfMapFormatVersion;
         private readonly bool _generateProfileFile;
         private readonly Func<MethodDesc, string> _printReproInstructions;
 
@@ -283,7 +283,7 @@ namespace ILCompiler
             string pdbPath,
             bool generatePerfMapFile,
             string perfMapPath,
-            Guid? perfMapMvid,
+            int perfMapFormatVersion,
             bool generateProfileFile,
             int parallelism,
             ProfileDataManager profileData,
@@ -309,7 +309,7 @@ namespace ILCompiler
             _pdbPath = pdbPath;
             _generatePerfMapFile = generatePerfMapFile;
             _perfMapPath = perfMapPath;
-            _perfMapMvid = perfMapMvid;
+            _perfMapFormatVersion = perfMapFormatVersion;
             _generateProfileFile = generateProfileFile;
             _customPESectionAlignment = customPESectionAlignment;
             SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory, verifyTypeAndFieldLayout);
@@ -347,6 +347,7 @@ namespace ILCompiler
                 ReadyToRunObjectWriter.EmitObject(
                     outputFile,
                     componentModule: null,
+                    inputFiles: _inputFiles,
                     nodes,
                     NodeFactory,
                     generateMapFile: _generateMapFile,
@@ -355,7 +356,7 @@ namespace ILCompiler
                     pdbPath: _pdbPath,
                     generatePerfMapFile: _generatePerfMapFile,
                     perfMapPath: _perfMapPath,
-                    perfMapMvid: _perfMapMvid,
+                    perfMapFormatVersion: _perfMapFormatVersion,
                     generateProfileFile: _generateProfileFile,
                     callChainProfile: _profileData.CallChainProfile,
                     _customPESectionAlignment);
@@ -427,6 +428,7 @@ namespace ILCompiler
             ReadyToRunObjectWriter.EmitObject(
                 outputFile,
                 componentModule: inputModule,
+                inputFiles: new string[] { inputFile },
                 componentGraph.MarkedNodeList,
                 componentFactory,
                 generateMapFile: false,
@@ -435,7 +437,7 @@ namespace ILCompiler
                 pdbPath: null,
                 generatePerfMapFile: false,
                 perfMapPath: null,
-                perfMapMvid: null,
+                perfMapFormatVersion: _perfMapFormatVersion,
                 generateProfileFile: false,
                 _profileData.CallChainProfile,
                 customPESectionAlignment: 0);
index fa4d318..c1207a4 100644 (file)
@@ -31,7 +31,7 @@ namespace ILCompiler
         private string _pdbPath;
         private bool _generatePerfMapFile;
         private string _perfMapPath;
-        private Guid? _perfMapMvid;
+        private int _perfMapFormatVersion;
         private bool _generateProfileFile;
         private int _parallelism;
         Func<MethodDesc, string> _printReproInstructions;
@@ -156,11 +156,11 @@ namespace ILCompiler
             return this;
         }
 
-        public ReadyToRunCodegenCompilationBuilder UsePerfMapFile(bool generatePerfMapFile, string perfMapPath, Guid? inputModuleMvid)
+        public ReadyToRunCodegenCompilationBuilder UsePerfMapFile(bool generatePerfMapFile, string perfMapPath, int perfMapFormatVersion)
         {
             _generatePerfMapFile = generatePerfMapFile;
             _perfMapPath = perfMapPath;
-            _perfMapMvid = inputModuleMvid;
+            _perfMapFormatVersion = perfMapFormatVersion;
             return this;
         }
 
@@ -312,7 +312,7 @@ namespace ILCompiler
                 pdbPath: _pdbPath,
                 generatePerfMapFile: _generatePerfMapFile,
                 perfMapPath: _perfMapPath,
-                perfMapMvid: _perfMapMvid,
+                perfMapFormatVersion: _perfMapFormatVersion,
                 generateProfileFile: _generateProfileFile,
                 _parallelism,
                 _profileData,
index 82145e3..ca6efc9 100644 (file)
@@ -106,6 +106,7 @@ namespace ILCompiler.PEWriter
     /// </summary>
     public class OutputInfoBuilder
     {
+        private readonly List<EcmaModule> _inputModules;
         private readonly List<OutputNode> _nodes;
         private readonly List<OutputSymbol> _symbols;
         private readonly List<Section> _sections;
@@ -117,6 +118,7 @@ namespace ILCompiler.PEWriter
 
         public OutputInfoBuilder()
         {
+            _inputModules = new List<EcmaModule>();
             _nodes = new List<OutputNode>();
             _symbols = new List<OutputSymbol>();
             _sections = new List<Section>();
@@ -127,6 +129,11 @@ namespace ILCompiler.PEWriter
             _relocCounts = new Dictionary<RelocType, int>();
         }
 
+        public void AddInputModule(EcmaModule module)
+        {
+            _inputModules.Add(module);
+        }
+
         public void AddNode(OutputNode node, ISymbolDefinitionNode symbol)
         {
             _nodes.Add(node);
@@ -197,6 +204,16 @@ namespace ILCompiler.PEWriter
             }
         }
 
+        public IEnumerable<AssemblyInfo> EnumerateInputAssemblies()
+        {
+            foreach (EcmaModule inputModule in _inputModules)
+            {
+                yield return new AssemblyInfo(
+                    inputModule.Assembly.GetName().Name,
+                    inputModule.MetadataReader.GetGuid(inputModule.MetadataReader.GetModuleDefinition().Mvid));
+            }
+        }
+
         private string FormatMethodName(MethodDesc method, TypeNameFormatter typeNameFormatter)
         {
             StringBuilder output = new StringBuilder();
index 7ec9357..8cd0ad4 100644 (file)
@@ -8,6 +8,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
+using Internal.TypeSystem;
 using ILCompiler.Diagnostics;
 
 namespace ILCompiler.PEWriter
@@ -28,12 +29,34 @@ namespace ILCompiler.PEWriter
             new PdbWriter(pdbPath, PDBExtraData.None).WritePDBData(dllFileName, _outputInfoBuilder.EnumerateMethods());
         }
 
-        public void SavePerfMap(string perfMapPath, string dllFileName, Guid? perfMapMvid)
+        public void SavePerfMap(string perfMapPath, int perfMapFormatVersion, string dllFileName, TargetOS targetOS, TargetArchitecture targetArch)
         {
-            string mvidComponent = (perfMapMvid.HasValue ? perfMapMvid.Value.ToString() : "composite");
-            string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + ".ni.{" + mvidComponent + "}.map");
+            string perfMapExtension;
+            if (perfMapFormatVersion == PerfMapWriter.LegacyCrossgen1FormatVersion)
+            {
+                string mvidComponent = null;
+                foreach (AssemblyInfo inputAssembly in _outputInfoBuilder.EnumerateInputAssemblies())
+                {
+                    if (mvidComponent == null)
+                    {
+                        mvidComponent = inputAssembly.Mvid.ToString();
+                    }
+                    else
+                    {
+                        mvidComponent = "composite";
+                        break;
+                    }
+                }
+                perfMapExtension = ".ni.{" + mvidComponent + "}.map";
+            }
+            else
+            {
+                perfMapExtension = ".ni.r2rmap";
+            }
+
+            string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + perfMapExtension);
             Console.WriteLine("Emitting PerfMap file: {0}", perfMapFileName);
-            PerfMapWriter.Write(perfMapFileName, _outputInfoBuilder.EnumerateMethods());
+            PerfMapWriter.Write(perfMapFileName, perfMapFormatVersion, _outputInfoBuilder.EnumerateMethods(), _outputInfoBuilder.EnumerateInputAssemblies(), targetOS, targetArch);
         }
     }
 }
index 1424375..0d332d5 100644 (file)
@@ -7,7 +7,7 @@
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
     <AssemblyKey>Open</AssemblyKey>
     <IsDotNetFrameworkProductAssembly>true</IsDotNetFrameworkProductAssembly>
-    <TargetFramework>netstandard2.0</TargetFramework>
+    <TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
     <CLSCompliant>false</CLSCompliant>
     <NoWarn>8002,NU1701</NoWarn>
     <RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers>
@@ -27,6 +27,9 @@
     <Compile Include="..\..\Common\Internal\Runtime\ReadyToRunConstants.cs" Link="Common\ReadyToRunConstants.cs" />
     <Compile Include="..\..\Common\Internal\Runtime\ReadyToRunInstructionSet.cs" Link="Common\ReadyToRunInstructionSet.cs" />
     <Compile Include="..\..\Common\Pgo\PgoFormat.cs" Link="Common\PgoFormat.cs" />
-    <Compile Include="..\..\Common\TypeSystem\Common\TargetArchitecture.cs" Link="Common\TargetArchitecture.cs" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\ILCompiler.TypeSystem.ReadyToRun\ILCompiler.TypeSystem.ReadyToRun.csproj" />
   </ItemGroup>
 </Project>
index f727ed8..821a38f 100644 (file)
@@ -5,6 +5,7 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Immutable;
 using System.IO;
+using System.Linq;
 using System.Reflection.Metadata;
 using System.Reflection.Metadata.Ecma335;
 using System.Reflection.PortableExecutable;
@@ -15,9 +16,9 @@ using System.Text;
 using Internal.CorConstants;
 using Internal.Runtime;
 using Internal.ReadyToRunConstants;
+using Internal.TypeSystem;
 
 using Debug = System.Diagnostics.Debug;
-using System.Linq;
 
 namespace ILCompiler.Reflection.ReadyToRun
 {
@@ -79,6 +80,8 @@ namespace ILCompiler.Reflection.ReadyToRun
 
     public sealed class ReadyToRunReader
     {
+        public const int GuidByteSize = 16;
+
         private const string SystemModuleName = "System.Private.CoreLib";
 
         /// <summary>
@@ -177,6 +180,33 @@ namespace ILCompiler.Reflection.ReadyToRun
         }
 
         /// <summary>
+        /// Conversion of the PE machine ID to TargetArchitecture used by TargetDetails.
+        /// </summary>
+        public TargetArchitecture TargetArchitecture
+        {
+            get
+            {
+                switch (Machine)
+                {
+                    case Machine.I386:
+                        return TargetArchitecture.X86;
+
+                    case Machine.Amd64:
+                        return TargetArchitecture.X64;
+
+                    case Machine.ArmThumb2:
+                        return TargetArchitecture.ARM;
+
+                    case Machine.Arm64:
+                        return TargetArchitecture.ARM64;
+
+                    default:
+                        throw new NotImplementedException(_machine.ToString());
+                }
+            }
+        }
+
+        /// <summary>
         /// Targeting operating system for the R2R executable
         /// </summary>
         public OperatingSystem OperatingSystem
@@ -189,6 +219,36 @@ namespace ILCompiler.Reflection.ReadyToRun
         }
 
         /// <summary>
+        /// Targeting operating system converted to the enumeration used by TargetDetails.
+        /// </summary>
+        public TargetOS TargetOperatingSystem
+        {
+            get
+            {
+                switch (OperatingSystem)
+                {
+                    case OperatingSystem.Windows:
+                        return TargetOS.Windows;
+
+                    case OperatingSystem.Linux:
+                        return TargetOS.Linux;
+
+                    case OperatingSystem.Apple:
+                        return TargetOS.OSX;
+
+                    case OperatingSystem.FreeBSD:
+                        return TargetOS.FreeBSD;
+
+                    case OperatingSystem.NetBSD:
+                        return TargetOS.FreeBSD;
+
+                    default:
+                        throw new NotImplementedException(OperatingSystem.ToString());
+                }
+            }
+        }
+
+        /// <summary>
         /// Targeting processor architecture of the R2R executable
         /// </summary>
         public Architecture Architecture
@@ -537,6 +597,12 @@ namespace ILCompiler.Reflection.ReadyToRun
             return (_composite ? null : _assemblyCache[0]);
         }
 
+        public string GetGlobalAssemblyName()
+        {
+            MetadataReader mdReader = GetGlobalMetadata().MetadataReader;
+            return mdReader.GetString(mdReader.GetAssemblyDefinition().Name);
+        }
+
         private unsafe void EnsureHeader()
         {
             if (_readyToRunHeader != null)
@@ -1087,6 +1153,26 @@ namespace ILCompiler.Reflection.ReadyToRun
             }
         }
 
+        public Guid GetAssemblyMvid(int assemblyIndex)
+        {
+            EnsureHeader();
+            if (_composite)
+            {
+                if (!ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.ManifestAssemblyMvids, out ReadyToRunSection mvidSection))
+                {
+                    return Guid.Empty;
+                }
+                int mvidOffset = GetOffset(mvidSection.RelativeVirtualAddress) + GuidByteSize * assemblyIndex;
+                return new Guid(new ReadOnlySpan<byte>(Image, mvidOffset, ReadyToRunReader.GuidByteSize));
+            }
+            else
+            {
+                Debug.Assert(assemblyIndex == 0);
+                MetadataReader mdReader = GetGlobalMetadata().MetadataReader;
+                return mdReader.GetGuid(mdReader.GetModuleDefinition().Mvid);
+            }
+        }
+
         /// <summary>
         /// Iterates through a native hashtable to get all RIDs
         /// </summary>
index 573b1eb..c91e615 100644 (file)
@@ -12,6 +12,8 @@ namespace ILCompiler
 {
     internal class CommandLineOptions
     {
+        public const int DefaultPerfMapFormatVersion = 0;
+
         public bool Help;
         public string HelpText;
 
@@ -56,6 +58,7 @@ namespace ILCompiler
         public string PdbPath;
         public bool PerfMap;
         public string PerfMapPath;
+        public int PerfMapFormatVersion;
         public int Parallelism;
         public int CustomPESectionAlignment;
         public string MethodLayout;
@@ -81,6 +84,7 @@ namespace ILCompiler
             MibcFilePaths = Array.Empty<string>();
             CodegenOptions = Array.Empty<string>();
 
+            PerfMapFormatVersion = DefaultPerfMapFormatVersion;
             Parallelism = Environment.ProcessorCount;
             SingleMethodGenericArg = null;
 
@@ -139,6 +143,7 @@ namespace ILCompiler
                 syntax.DefineOption("pdb-path", ref PdbPath, SR.PdbFilePathOption);
                 syntax.DefineOption("perfmap", ref PerfMap, SR.PerfMapFileOption);
                 syntax.DefineOption("perfmap-path", ref PerfMapPath, SR.PerfMapFilePathOption);
+                syntax.DefineOption("perfmap-format-version", ref PerfMapFormatVersion, SR.PerfMapFormatVersionOption);
 
                 syntax.DefineOption("method-layout", ref MethodLayout, SR.MethodLayoutOption);
                 syntax.DefineOption("file-layout", ref FileLayout, SR.FileLayoutOption);
index 2f84f6f..aeeb9f5 100644 (file)
@@ -517,7 +517,6 @@ namespace ILCompiler
 
                     List<EcmaModule> inputModules = new List<EcmaModule>();
                     List<EcmaModule> rootingModules = new List<EcmaModule>();
-                    Guid? inputModuleMvid = null;
 
                     foreach (var inputFile in inFilePaths)
                     {
@@ -526,10 +525,6 @@ namespace ILCompiler
                         rootingModules.Add(module);
                         versionBubbleModulesHash.Add(module);
 
-                        if (!_commandLineOptions.Composite && !inputModuleMvid.HasValue)
-                        {
-                            inputModuleMvid = module.MetadataReader.GetGuid(module.MetadataReader.GetModuleDefinition().Mvid);
-                        }
 
                         if (!_commandLineOptions.CompositeOrInputBubble)
                         {
@@ -687,7 +682,7 @@ namespace ILCompiler
                         .UseMapFile(_commandLineOptions.Map)
                         .UseMapCsvFile(_commandLineOptions.MapCsv)
                         .UsePdbFile(_commandLineOptions.Pdb, _commandLineOptions.PdbPath)
-                        .UsePerfMapFile(_commandLineOptions.PerfMap, _commandLineOptions.PerfMapPath, inputModuleMvid)
+                        .UsePerfMapFile(_commandLineOptions.PerfMap, _commandLineOptions.PerfMapPath, _commandLineOptions.PerfMapFormatVersion)
                         .UseProfileFile(jsonProfile != null)
                         .UseParallelism(_commandLineOptions.Parallelism)
                         .UseProfileData(profileDataManager)
index 084138e..c031f30 100644 (file)
   <data name="PerfMapFilePathOption" xml:space="preserve">
     <value>Explicit specification of the PerfMap file path</value>
   </data>
-</root>
+  <data name="PerfMapFormatVersionOption" xml:space="preserve">
+    <value>Explicitly request a particular PerfMap format version</value>
+  </data>
+</root>
\ No newline at end of file
index 8857cdb..9a1296b 100644 (file)
@@ -40,6 +40,7 @@ namespace R2RDump
             command.AddOption(new Option<string>(new[] { "--pdb-path" }, "PDB output path for --create-pdb"));
             command.AddOption(new Option<bool>(new[] { "--create-perfmap" }, "Create PerfMap"));
             command.AddOption(new Option<string>(new[] { "--perfmap-path" }, "PerfMap output path for --create-perfmap"));
+            command.AddOption(new Option<int>(new[] { "--perfmap-format-version" }, "PerfMap format version for --create-perfmap"));
             return command;
         }
     }
index 8a24273..94d7183 100644 (file)
@@ -20,6 +20,7 @@ using ILCompiler.Diagnostics;
 using ILCompiler.Reflection.ReadyToRun;
 
 using Internal.Runtime;
+using Internal.TypeSystem;
 
 namespace R2RDump
 {
@@ -55,6 +56,7 @@ namespace R2RDump
 
         public bool CreatePerfmap { get; set; }
         public string PerfmapPath { get; set; }
+        public int PerfmapFormatVersion { get; set; }
 
 
         public FileInfo[] Reference { get; set; }
@@ -65,6 +67,11 @@ namespace R2RDump
 
         private SignatureFormattingOptions signatureFormattingOptions;
 
+        public DumpOptions()
+        {
+            PerfmapFormatVersion = PerfMapWriter.CurrentFormatVersion;
+        }
+
         /// <summary>
         /// Probing extensions to use when looking up assemblies under reference paths.
         /// </summary>
@@ -425,9 +432,9 @@ namespace R2RDump
                     string perfmapPath = _options.PerfmapPath;
                     if (string.IsNullOrEmpty(perfmapPath))
                     {
-                        perfmapPath = Path.ChangeExtension(r2r.Filename, ".map");
-                        PerfMapWriter.Write(perfmapPath, ProduceDebugInfoMethods(r2r));
+                        perfmapPath = Path.ChangeExtension(r2r.Filename, ".r2rmap");
                     }
+                    PerfMapWriter.Write(perfmapPath, _options.PerfmapFormatVersion, ProduceDebugInfoMethods(r2r), ProduceDebugInfoAssemblies(r2r), r2r.TargetOperatingSystem, r2r.TargetArchitecture);
                 }
 
                 if (standardDump)
@@ -457,6 +464,21 @@ namespace R2RDump
             }
         }
 
+        IEnumerable<AssemblyInfo> ProduceDebugInfoAssemblies(ReadyToRunReader r2r)
+        {
+            if (r2r.Composite)
+            {
+                foreach (KeyValuePair<string, int> kvpRefAssembly in r2r.ManifestReferenceAssemblies.OrderBy(kvp => kvp.Key, StringComparer.OrdinalIgnoreCase))
+                {
+                    yield return new AssemblyInfo(kvpRefAssembly.Key, r2r.GetAssemblyMvid(kvpRefAssembly.Value));
+                }
+            }
+            else
+            {
+                yield return new AssemblyInfo(r2r.GetGlobalAssemblyName(), r2r.GetAssemblyMvid(0));
+            }
+        }
+
         /// <summary>
         /// Returns true if the name, signature or id of <param>method</param> matches <param>query</param>
         /// </summary>
index 6596a59..e8f71be 100644 (file)
@@ -8,38 +8,89 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.Reflection.Ready
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.Diagnostics", "..\aot\ILCompiler.Diagnostics\ILCompiler.Diagnostics.csproj", "{4E9512BA-F963-472A-B689-37D4D32456F3}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.TypeSystem.ReadyToRun", "..\aot\ILCompiler.TypeSystem.ReadyToRun\ILCompiler.TypeSystem.ReadyToRun.csproj", "{F9CC5645-9E5D-41EE-ACD3-120F661DDA51}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Checked|Any CPU = Checked|Any CPU
+               Checked|x64 = Checked|x64
+               Checked|x86 = Checked|x86
                Debug|Any CPU = Debug|Any CPU
                Debug|x64 = Debug|x64
+               Debug|x86 = Debug|x86
                Release|Any CPU = Release|Any CPU
                Release|x64 = Release|x64
+               Release|x86 = Release|x86
        EndGlobalSection
        GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|Any CPU.ActiveCfg = Release|Any CPU
+               {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|Any CPU.Build.0 = Release|Any CPU
+               {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|x64.ActiveCfg = Release|x64
+               {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|x64.Build.0 = Release|x64
+               {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|x86.ActiveCfg = Debug|x86
+               {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|x86.Build.0 = Debug|x86
                {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|Any CPU.ActiveCfg = Debug|x64
                {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|Any CPU.Build.0 = Debug|x64
                {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|x64.ActiveCfg = Debug|x64
                {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|x64.Build.0 = Debug|x64
+               {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|x86.ActiveCfg = Debug|x86
+               {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|x86.Build.0 = Debug|x86
                {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|Any CPU.Build.0 = Release|Any CPU
                {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|x64.ActiveCfg = Release|x64
                {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|x64.Build.0 = Release|x64
+               {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|x86.ActiveCfg = Release|x86
+               {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|x86.Build.0 = Release|x86
+               {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|Any CPU.ActiveCfg = Release|Any CPU
+               {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|Any CPU.Build.0 = Release|Any CPU
+               {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|x64.ActiveCfg = Release|x64
+               {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|x64.Build.0 = Release|x64
+               {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|x86.ActiveCfg = Release|Any CPU
+               {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|x86.Build.0 = Release|Any CPU
                {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|Any CPU.Build.0 = Debug|Any CPU
                {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|x64.ActiveCfg = Debug|x64
                {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|x64.Build.0 = Debug|x64
+               {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|x86.Build.0 = Debug|Any CPU
                {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|Any CPU.Build.0 = Release|Any CPU
                {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|x64.ActiveCfg = Release|x64
                {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|x64.Build.0 = Release|x64
+               {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|x86.ActiveCfg = Release|Any CPU
+               {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|x86.Build.0 = Release|Any CPU
+               {4E9512BA-F963-472A-B689-37D4D32456F3}.Checked|Any CPU.ActiveCfg = Checked|x86
+               {4E9512BA-F963-472A-B689-37D4D32456F3}.Checked|x64.ActiveCfg = Checked|x64
+               {4E9512BA-F963-472A-B689-37D4D32456F3}.Checked|x64.Build.0 = Checked|x64
+               {4E9512BA-F963-472A-B689-37D4D32456F3}.Checked|x86.ActiveCfg = Checked|x86
+               {4E9512BA-F963-472A-B689-37D4D32456F3}.Checked|x86.Build.0 = Checked|x86
                {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|Any CPU.ActiveCfg = Debug|x64
                {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|Any CPU.Build.0 = Debug|x64
                {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|x64.ActiveCfg = Debug|x64
                {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|x64.Build.0 = Debug|x64
+               {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|x86.ActiveCfg = Debug|x86
+               {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|x86.Build.0 = Debug|x86
                {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|Any CPU.Build.0 = Release|Any CPU
                {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|x64.ActiveCfg = Release|Any CPU
                {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|x64.Build.0 = Release|Any CPU
+               {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|x86.ActiveCfg = Release|x86
+               {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|x86.Build.0 = Release|x86
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Checked|Any CPU.ActiveCfg = Checked|x86
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Checked|x64.ActiveCfg = Checked|x64
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Checked|x64.Build.0 = Checked|x64
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Checked|x86.ActiveCfg = Checked|x86
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Checked|x86.Build.0 = Checked|x86
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Debug|Any CPU.ActiveCfg = Debug|x86
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Debug|x64.ActiveCfg = Debug|x64
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Debug|x64.Build.0 = Debug|x64
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Debug|x86.ActiveCfg = Debug|x86
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Debug|x86.Build.0 = Debug|x86
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Release|Any CPU.ActiveCfg = Release|x86
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Release|x64.ActiveCfg = Release|x64
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Release|x64.Build.0 = Release|x64
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Release|x86.ActiveCfg = Release|x86
+               {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Release|x86.Build.0 = Release|x86
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
index 0e062b8..7ca2b58 100644 (file)
@@ -7,6 +7,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection.Metadata;
 using System.Reflection.Metadata.Ecma335;
+using System.Runtime.CompilerServices;
 using System.Reflection.PortableExecutable;
 using System.Text;
 
@@ -18,8 +19,6 @@ namespace R2RDump
 {
     class TextDumper : Dumper
     {
-        private const int GuidByteSize = 16;
-
         public TextDumper(ReadyToRunReader r2r, TextWriter writer, Disassembler disassembler, DumpOptions options)
             : base(r2r, writer, disassembler, options)
         {
@@ -90,14 +89,8 @@ namespace R2RDump
                     int assemblyIndex = 0;
                     foreach (string assemblyName in _r2r.ManifestReferenceAssemblies.OrderBy(kvp => kvp.Value).Select(kvp => kvp.Key))
                     {
-                        string dividerName = $@"Component Assembly [{assemblyIndex}]: {assemblyName}";
-                        if (_r2r.ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.ManifestAssemblyMvids, out ReadyToRunSection mvidSection))
-                        {
-                            int mvidOffset = _r2r.GetOffset(mvidSection.RelativeVirtualAddress) + GuidByteSize * assemblyIndex;
-                            Guid mvid = new Guid(new ReadOnlySpan<byte>(_r2r.Image, mvidOffset, GuidByteSize));
-                            dividerName += $@" - MVID {mvid:b}";
-                        }
-                        WriteDivider(dividerName);
+                        Guid mvid = _r2r.GetAssemblyMvid(assemblyIndex);
+                        WriteDivider($@"Component Assembly [{assemblyIndex}]: {assemblyName} - MVID {mvid:b}");
                         ReadyToRunCoreHeader assemblyHeader = _r2r.ReadyToRunAssemblyHeaders[assemblyIndex];
                         foreach (ReadyToRunSection section in NormalizedSections(assemblyHeader))
                         {
@@ -513,12 +506,10 @@ namespace R2RDump
                     _writer.WriteLine("Composite executable: {0}", ownerCompositeExecutable.ToEscapedString());
                     break;
                 case ReadyToRunSectionType.ManifestAssemblyMvids:
-                    int mvidOffset = _r2r.GetOffset(section.RelativeVirtualAddress);
-                    int mvidCount = section.Size / GuidByteSize;
+                    int mvidCount = section.Size / ReadyToRunReader.GuidByteSize;
                     for (int mvidIndex = 0; mvidIndex < mvidCount; mvidIndex++)
                     {
-                        Guid mvid = new Guid(new Span<byte>(_r2r.Image, mvidOffset + GuidByteSize * mvidIndex, GuidByteSize));
-                        _writer.WriteLine("MVID[{0}] = {1:b}", mvidIndex, mvid);
+                        _writer.WriteLine("MVID[{0}] = {1:b}", mvidIndex, _r2r.GetAssemblyMvid(mvidIndex));
                     }
                     break;
                 default: