diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj index 5f270b3e8951f..8c9419db564aa 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj @@ -1,12 +1,12 @@ - Library ILCompiler.Diagnostics + Library + true $(NetCoreAppToolCurrent) READYTORUN;$(DefineConstants) - false - x64;x86 + x64;x86;arm;arm64 AnyCPU false diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs index bab76a267f4a2..e822d20c6f75d 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs @@ -50,11 +50,21 @@ internal class ReadyToRunObjectWriter /// private readonly IEnumerable _nodes; + /// + /// Set to non-null when the executable generator should output a map or symbol file. + /// + private readonly ObjectInfoBuilder _objectInfoBuilder; + /// /// Set to non-null when the executable generator should output a map file. /// private readonly MapFileBuilder _mapFileBuilder; + /// + /// Set to non-null when generating symbol info (PDB / PerfMap). + /// + private readonly SymbolFileBuilder _symbolFileBuilder; + /// /// True when the map file builder should emit a textual map file /// @@ -133,10 +143,23 @@ public ReadyToRunObjectWriter( _pdbPath = pdbPath; _generatePerfMapFile = generatePerfMapFile; _perfMapPath = perfMapPath; - - if (generateMapFile || generateMapCsvFile || generatePdbFile || generatePerfMapFile) + + bool generateMap = (generateMapFile || generateMapCsvFile); + bool generateSymbols = (generatePdbFile || generatePerfMapFile); + + if (generateMap || generateSymbols) { - _mapFileBuilder = new MapFileBuilder(); + _objectInfoBuilder = new ObjectInfoBuilder(); + + if (generateMap) + { + _mapFileBuilder = new MapFileBuilder(_objectInfoBuilder); + } + + if (generateSymbols) + { + _symbolFileBuilder = new SymbolFileBuilder(_objectInfoBuilder); + } } } @@ -244,12 +267,12 @@ public void EmitPortableExecutable() } } - EmitObjectData(r2rPeBuilder, nodeContents, nodeIndex, name, node.Section, _mapFileBuilder); + EmitObjectData(r2rPeBuilder, nodeContents, nodeIndex, name, node.Section); lastWrittenObjectNode = node; if ((_generatePdbFile || _generatePerfMapFile) && node is MethodWithGCInfo methodNode) { - _mapFileBuilder.AddMethod(methodNode, nodeContents.DefinedSymbols[0]); + _objectInfoBuilder.AddMethod(methodNode, nodeContents.DefinedSymbols[0]); } } @@ -289,9 +312,9 @@ public void EmitPortableExecutable() } } - if (_mapFileBuilder != null) + if (_objectInfoBuilder != null) { - r2rPeBuilder.AddSections(_mapFileBuilder); + r2rPeBuilder.AddSections(_objectInfoBuilder); if (_generateMapFile) { @@ -313,7 +336,7 @@ public void EmitPortableExecutable() { path = Path.GetDirectoryName(_objectFilePath); } - _mapFileBuilder.SavePdb(path, _objectFilePath); + _symbolFileBuilder.SavePdb(path, _objectFilePath); } if (_generatePerfMapFile) @@ -323,7 +346,7 @@ public void EmitPortableExecutable() { path = Path.GetDirectoryName(_objectFilePath); } - _mapFileBuilder.SavePerfMap(path, _objectFilePath); + _symbolFileBuilder.SavePerfMap(path, _objectFilePath); } } @@ -361,8 +384,7 @@ public void EmitPortableExecutable() /// Logical index of the emitted node for diagnostic purposes /// Textual representation of the ObjecData blob in the map file /// Section to emit the blob into - /// Map file output stream - private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int nodeIndex, string name, ObjectNodeSection section, MapFileBuilder mapFileBuilder) + private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int nodeIndex, string name, ObjectNodeSection section) { #if DEBUG for (int symbolIndex = 0; symbolIndex < data.DefinedSymbols.Length; symbolIndex++) @@ -381,7 +403,7 @@ private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int node } #endif - r2rPeBuilder.AddObjectData(data, section, name, mapFileBuilder); + r2rPeBuilder.AddObjectData(data, section, name, _objectInfoBuilder); } public static void EmitObject( diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 9058459d10f0f..9aad5df004409 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -6,7 +6,7 @@ true READYTORUN;$(DefineConstants) false - x64;x86 + x64;x86;arm;arm64 AnyCPU false @@ -196,6 +196,8 @@ + + diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/MapFileBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/MapFileBuilder.cs index 21d33cbbe2f3c..8289896c3162c 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/MapFileBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/MapFileBuilder.cs @@ -21,87 +21,6 @@ namespace ILCompiler.PEWriter { - /// - /// Base class for symbols and nodes in the map file implements common logic - /// for section / offset ordering. - /// - public class MapFileItem - { - public class Comparer : IComparer - { - public readonly static Comparer Instance = new Comparer(); - - public int Compare([AllowNull] MapFileItem x, [AllowNull] MapFileItem y) - { - return (x.SectionIndex != y.SectionIndex ? x.SectionIndex.CompareTo(y.SectionIndex) : x.Offset.CompareTo(y.Offset)); - } - } - - /// - /// Item section index - /// - public readonly int SectionIndex; - - /// - /// Offset relative to section beginning - /// - public readonly int Offset; - - /// - /// Item name - /// - public readonly string Name; - - public MapFileItem(int sectionIndex, int offset, string name) - { - SectionIndex = sectionIndex; - Offset = offset; - Name = name; - } - } - - /// - /// This class represents a single node (contiguous block of data) in the output R2R PE file. - /// - public class MapFileNode : MapFileItem - { - /// - /// Node length (number of bytes). This doesn't include any external alignment - /// applied when concatenating the nodes to form sections. - /// - public readonly int Length; - - /// - /// Number of file-level relocations (.reloc section entries) used by the node. - /// - public int Relocations { get; private set; } - - public MapFileNode(int sectionIndex, int offset, int length, string name) - : base(sectionIndex, offset, name) - { - Length = length; - Relocations = 0; - } - - public void AddRelocation() - { - Relocations++; - } - } - - /// - /// Symbol is a "pointer" into the PE file. Most (but not all) symbols correspond to - /// node beginnings (most nodes have a "start symbol" representing the beginning - /// of the node). - /// - public class MapFileSymbol : MapFileItem - { - public MapFileSymbol(int sectionIndex, int offset, string name) - : base(sectionIndex, offset, name) - { - } - } - /// /// Helper class used to collect information to be output into the map file. /// @@ -127,7 +46,7 @@ public NodeTypeStatistics(string name) Name = name; } - public void AddNode(MapFileNode node) + public void AddNode(ObjectNode node) { Debug.Assert(Name == node.Name); Count++; @@ -135,55 +54,13 @@ public void AddNode(MapFileNode node) } } - private readonly List _nodes; - private readonly List _symbols; - private readonly List
_sections; - - private readonly Dictionary _nodeSymbolMap; - private readonly Dictionary _methodSymbolMap; - - private readonly Dictionary _relocCounts; + private ObjectInfoBuilder _objectInfoBuilder; private long _fileSize; - public MapFileBuilder() - { - _nodes = new List(); - _symbols = new List(); - _sections = new List
(); - - _nodeSymbolMap = new Dictionary(); - _methodSymbolMap = new Dictionary(); - - _relocCounts = new Dictionary(); - } - - public void AddNode(MapFileNode node, ISymbolDefinitionNode symbol) - { - _nodes.Add(node); - _nodeSymbolMap.Add(symbol, node); - } - - public void AddRelocation(MapFileNode node, RelocType relocType) + public MapFileBuilder(ObjectInfoBuilder objectInfoBuilder) { - node.AddRelocation(); - _relocCounts.TryGetValue(relocType, out int relocTypeCount); - _relocCounts[relocType] = relocTypeCount + 1; - } - - public void AddSymbol(MapFileSymbol symbol) - { - _symbols.Add(symbol); - } - - public void AddSection(Section section) - { - _sections.Add(section); - } - - public void AddMethod(MethodWithGCInfo method, ISymbolDefinitionNode symbol) - { - _methodSymbolMap.Add(symbol, method); + _objectInfoBuilder = objectInfoBuilder; } public void SetFileSize(long fileSize) @@ -195,8 +72,7 @@ public void SaveMap(string mapFileName) { Console.WriteLine("Emitting map file: {0}", mapFileName); - _nodes.Sort(MapFileItem.Comparer.Instance); - _symbols.Sort(MapFileItem.Comparer.Instance); + _objectInfoBuilder.Sort(); using (StreamWriter mapWriter = new StreamWriter(mapFileName)) { @@ -212,8 +88,7 @@ public void SaveCsv(string nodeStatsCsvFileName, string mapCsvFileName) { Console.WriteLine("Emitting csv files: {0}, {1}", nodeStatsCsvFileName, mapCsvFileName); - _nodes.Sort(MapFileItem.Comparer.Instance); - _symbols.Sort(MapFileItem.Comparer.Instance); + _objectInfoBuilder.Sort(); using (StreamWriter nodeStatsWriter = new StreamWriter(nodeStatsCsvFileName)) { @@ -226,37 +101,22 @@ public void SaveCsv(string nodeStatsCsvFileName, string mapCsvFileName) } } - public void SavePdb(string pdbPath, string dllFileName) - { - Console.WriteLine("Emitting PDB file: {0}", Path.Combine(pdbPath, Path.GetFileNameWithoutExtension(dllFileName) + ".ni.pdb")); - - new PdbWriter(pdbPath, PDBExtraData.None).WritePDBData(dllFileName, EnumerateMethods()); - } - - public void SavePerfMap(string perfMapPath, string dllFileName) - { - string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + ".perf.map"); - Console.WriteLine("Emitting PerfMap file: {0}", perfMapFileName); - - PerfMapWriter.Write(perfMapFileName, EnumerateMethods()); - } - private void WriteHeader(StreamWriter writer) { WriteTitle(writer, "Summary Info"); writer.WriteLine($"Output file size: {_fileSize,10}"); - writer.WriteLine($"Section count: {_sections.Count,10}"); - writer.WriteLine($"Node count: {_nodes.Count,10}"); - writer.WriteLine($"Symbol count: {_symbols.Count,10}"); - writer.WriteLine($"Relocation count: {_relocCounts.Values.Sum(),10}"); + writer.WriteLine($"Section count: {_objectInfoBuilder.Sections.Count,10}"); + writer.WriteLine($"Node count: {_objectInfoBuilder.Nodes.Count,10}"); + writer.WriteLine($"Symbol count: {_objectInfoBuilder.Symbols.Count,10}"); + writer.WriteLine($"Relocation count: {_objectInfoBuilder.RelocCounts.Values.Sum(),10}"); } private IEnumerable GetNodeTypeStatistics() { List nodeTypeStats = new List(); Dictionary statsNameIndex = new Dictionary(); - foreach (MapFileNode node in _nodes) + foreach (ObjectNode node in _objectInfoBuilder.Nodes) { if (!statsNameIndex.TryGetValue(node.Name, out int statsIndex)) { @@ -304,7 +164,7 @@ private void WriteNodeTypeStatisticsCsv(StreamWriter writer) private void WriteRelocTypeStatistics(StreamWriter writer) { - KeyValuePair[] relocTypeCounts = _relocCounts.ToArray(); + KeyValuePair[] relocTypeCounts = _objectInfoBuilder.RelocCounts.ToArray(); Array.Sort(relocTypeCounts, (a, b) => b.Value.CompareTo(a.Value)); WriteTitle(writer, "Reloc Type Statistics"); @@ -320,13 +180,12 @@ private void WriteRelocTypeStatistics(StreamWriter writer) WriteTitle(writer, "Top Nodes By Relocation Count"); WriteTitle(writer, " COUNT | SYMBOL (NODE)"); - foreach (MapFileNode node in _nodes.Where(node => node.Relocations != 0).OrderByDescending(node => node.Relocations).Take(NumberOfTopNodesByRelocType)) + foreach (ObjectNode node in _objectInfoBuilder.Nodes.Where(node => node.Relocations != 0).OrderByDescending(node => node.Relocations).Take(NumberOfTopNodesByRelocType)) { writer.Write($"{node.Relocations,8} | "); - int symbolIndex = _symbols.BinarySearch(new MapFileSymbol(node.SectionIndex, node.Offset, name: null), MapFileItem.Comparer.Instance); - if (symbolIndex >= 0 && symbolIndex < _symbols.Count && MapFileItem.Comparer.Instance.Compare(_symbols[symbolIndex], node) == 0) + if (_objectInfoBuilder.FindSymbol(node, out int symbolIndex)) { - writer.Write($"{_symbols[symbolIndex].Name}"); + writer.Write($"{_objectInfoBuilder.Symbols[symbolIndex].Name}"); } writer.WriteLine($" ({node.Name})"); } @@ -336,9 +195,9 @@ private void WriteSections(StreamWriter writer) { WriteTitle(writer, "Section Map"); WriteTitle(writer, "INDEX | FILEOFFSET | RVA | END_RVA | LENGTH | NAME"); - for (int sectionIndex = 0; sectionIndex < _sections.Count; sectionIndex++) + for (int sectionIndex = 0; sectionIndex < _objectInfoBuilder.Sections.Count; sectionIndex++) { - Section section = _sections[sectionIndex]; + Section section = _objectInfoBuilder.Sections[sectionIndex]; writer.Write($"{sectionIndex,5} | "); writer.Write($"0x{section.FilePosWhenPlaced:X8} | "); writer.Write($"0x{section.RVAWhenPlaced:X8} | "); @@ -356,13 +215,15 @@ private void WriteMap(StreamWriter writer) int nodeIndex = 0; int symbolIndex = 0; - while (nodeIndex < _nodes.Count || symbolIndex < _symbols.Count) + while (nodeIndex < _objectInfoBuilder.Nodes.Count || symbolIndex < _objectInfoBuilder.Symbols.Count) { - if (nodeIndex >= _nodes.Count || symbolIndex < _symbols.Count && MapFileItem.Comparer.Instance.Compare(_symbols[symbolIndex], _nodes[nodeIndex]) < 0) + if (nodeIndex >= _objectInfoBuilder.Nodes.Count + || symbolIndex < _objectInfoBuilder.Symbols.Count + && ObjectItem.Comparer.Instance.Compare(_objectInfoBuilder.Symbols[symbolIndex], _objectInfoBuilder.Nodes[nodeIndex]) < 0) { // No more nodes or next symbol is below next node - emit symbol - MapFileSymbol symbol = _symbols[symbolIndex++]; - Section section = _sections[symbol.SectionIndex]; + ObjectSymbol symbol = _objectInfoBuilder.Symbols[symbolIndex++]; + Section section = _objectInfoBuilder.Sections[symbol.SectionIndex]; writer.Write($"0x{symbol.Offset + section.RVAWhenPlaced:X8} | "); writer.Write(" | "); writer.Write(" | "); @@ -372,16 +233,16 @@ private void WriteMap(StreamWriter writer) else { // Emit node and optionally symbol - MapFileNode node = _nodes[nodeIndex++]; - Section section = _sections[node.SectionIndex]; + ObjectNode node = _objectInfoBuilder.Nodes[nodeIndex++]; + Section section = _objectInfoBuilder.Sections[node.SectionIndex]; writer.Write($"0x{node.Offset + section.RVAWhenPlaced:X8} | "); writer.Write($"0x{node.Length:X6} | "); writer.Write($"{node.Relocations,6} | "); writer.Write($"{GetNameHead(section),-SectionNameHeadLength} | "); - if (symbolIndex < _symbols.Count && MapFileItem.Comparer.Instance.Compare(node, _symbols[symbolIndex]) == 0) + if (symbolIndex < _objectInfoBuilder.Symbols.Count && ObjectItem.Comparer.Instance.Compare(node, _objectInfoBuilder.Symbols[symbolIndex]) == 0) { - MapFileSymbol symbol = _symbols[symbolIndex++]; + ObjectSymbol symbol = _objectInfoBuilder.Symbols[symbolIndex++]; writer.Write($"{symbol.Name}"); } writer.WriteLine($" ({node.Name})"); @@ -396,13 +257,15 @@ private void WriteMapCsv(StreamWriter writer) int nodeIndex = 0; int symbolIndex = 0; - while (nodeIndex < _nodes.Count || symbolIndex < _symbols.Count) + while (nodeIndex < _objectInfoBuilder.Nodes.Count || symbolIndex < _objectInfoBuilder.Symbols.Count) { - if (nodeIndex >= _nodes.Count || symbolIndex < _symbols.Count && MapFileItem.Comparer.Instance.Compare(_symbols[symbolIndex], _nodes[nodeIndex]) < 0) + if (nodeIndex >= _objectInfoBuilder.Nodes.Count + || symbolIndex < _objectInfoBuilder.Symbols.Count + && ObjectItem.Comparer.Instance.Compare(_objectInfoBuilder.Symbols[symbolIndex], _objectInfoBuilder.Nodes[nodeIndex]) < 0) { // No more nodes or next symbol is below next node - emit symbol - MapFileSymbol symbol = _symbols[symbolIndex++]; - Section section = _sections[symbol.SectionIndex]; + ObjectSymbol symbol = _objectInfoBuilder.Symbols[symbolIndex++]; + Section section = _objectInfoBuilder.Sections[symbol.SectionIndex]; writer.Write($"0x{symbol.Offset + section.RVAWhenPlaced:X8},"); writer.Write(","); writer.Write(","); @@ -413,16 +276,16 @@ private void WriteMapCsv(StreamWriter writer) else { // Emit node and optionally symbol - MapFileNode node = _nodes[nodeIndex++]; - Section section = _sections[node.SectionIndex]; + ObjectNode node = _objectInfoBuilder.Nodes[nodeIndex++]; + Section section = _objectInfoBuilder.Sections[node.SectionIndex]; writer.Write($"0x{node.Offset + section.RVAWhenPlaced:X8},"); writer.Write($"{node.Length},"); writer.Write($"{node.Relocations},"); writer.Write($"{section.Name},"); - if (symbolIndex < _symbols.Count && MapFileItem.Comparer.Instance.Compare(node, _symbols[symbolIndex]) == 0) + if (symbolIndex < _objectInfoBuilder.Symbols.Count && ObjectItem.Comparer.Instance.Compare(node, _objectInfoBuilder.Symbols[symbolIndex]) == 0) { - MapFileSymbol symbol = _symbols[symbolIndex++]; + ObjectSymbol symbol = _objectInfoBuilder.Symbols[symbolIndex++]; writer.Write($"{symbol.Name}"); } writer.Write(","); @@ -448,53 +311,5 @@ private void WriteTitle(StreamWriter writer, string title) writer.WriteLine(new string('-', title.Length)); } - private IEnumerable EnumerateMethods() - { - DebugNameFormatter nameFormatter = new DebugNameFormatter(); - TypeNameFormatter typeNameFormatter = new TypeString(); - HashSet emittedMethods = new HashSet(); - foreach (KeyValuePair symbolMethodPair in _methodSymbolMap) - { - EcmaMethod ecmaMethod = symbolMethodPair.Value.Method.GetTypicalMethodDefinition() as EcmaMethod; - if (ecmaMethod != null && emittedMethods.Add(ecmaMethod)) - { - MethodInfo methodInfo = new MethodInfo(); - methodInfo.MethodToken = (uint)MetadataTokens.GetToken(ecmaMethod.Handle); - methodInfo.AssemblyName = ecmaMethod.Module.Assembly.GetName().Name; - methodInfo.Name = FormatMethodName(symbolMethodPair.Value.Method, typeNameFormatter); - MapFileNode node = _nodeSymbolMap[symbolMethodPair.Key]; - Section section = _sections[node.SectionIndex]; - methodInfo.HotRVA = (uint)(section.RVAWhenPlaced + node.Offset); - methodInfo.HotLength = (uint)node.Length; - methodInfo.ColdRVA = 0; - methodInfo.ColdLength = 0; - yield return methodInfo; - } - } - } - - private string FormatMethodName(MethodDesc method, TypeNameFormatter typeNameFormatter) - { - StringBuilder output = new StringBuilder(); - if (!method.Signature.ReturnType.IsVoid) - { - output.Append(typeNameFormatter.FormatName(method.Signature.ReturnType)); - output.Append(" "); - } - output.Append(typeNameFormatter.FormatName(method.OwningType)); - output.Append("::"); - output.Append(method.Name); - output.Append("("); - for (int paramIndex = 0; paramIndex < method.Signature.Length; paramIndex++) - { - if (paramIndex != 0) - { - output.Append(", "); - } - output.Append(typeNameFormatter.FormatName(method.Signature[paramIndex])); - } - output.Append(")"); - return output.ToString(); - } } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/ObjectInfoBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/ObjectInfoBuilder.cs new file mode 100644 index 0000000000000..29634dbdc2e94 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/ObjectInfoBuilder.cs @@ -0,0 +1,230 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +using Internal.JitInterface; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +using ILCompiler.DependencyAnalysis; +using ILCompiler.DependencyAnalysis.ReadyToRun; +using ILCompiler.Diagnostics; + +namespace ILCompiler.PEWriter +{ + /// + /// Base class for symbols and nodes in the output file implements common logic + /// for section / offset ordering. + /// + public class ObjectItem + { + public class Comparer : IComparer + { + public readonly static Comparer Instance = new Comparer(); + + public int Compare([AllowNull] ObjectItem x, [AllowNull] ObjectItem y) + { + return (x.SectionIndex != y.SectionIndex ? x.SectionIndex.CompareTo(y.SectionIndex) : x.Offset.CompareTo(y.Offset)); + } + } + + /// + /// Item section index + /// + public readonly int SectionIndex; + + /// + /// Offset relative to section beginning + /// + public readonly int Offset; + + /// + /// Item name + /// + public readonly string Name; + + public ObjectItem(int sectionIndex, int offset, string name) + { + SectionIndex = sectionIndex; + Offset = offset; + Name = name; + } + } + + /// + /// This class represents a single node (contiguous block of data) in the output R2R PE file. + /// + public class ObjectNode : ObjectItem + { + /// + /// Node length (number of bytes). This doesn't include any external alignment + /// applied when concatenating the nodes to form sections. + /// + public readonly int Length; + + /// + /// Number of file-level relocations (.reloc section entries) used by the node. + /// + public int Relocations { get; private set; } + + public ObjectNode(int sectionIndex, int offset, int length, string name) + : base(sectionIndex, offset, name) + { + Length = length; + Relocations = 0; + } + + public void AddRelocation() + { + Relocations++; + } + } + + /// + /// Symbol is a "pointer" into the PE file. Most (but not all) symbols correspond to + /// node beginnings (most nodes have a "start symbol" representing the beginning + /// of the node). + /// + public class ObjectSymbol : ObjectItem + { + public ObjectSymbol(int sectionIndex, int offset, string name) + : base(sectionIndex, offset, name) + { + } + } + + /// + /// Common class used to collect information to use when emitting map files and symbol files. + /// + public class ObjectInfoBuilder + { + private readonly List _nodes; + private readonly List _symbols; + private readonly List
_sections; + + private readonly Dictionary _nodeSymbolMap; + private readonly Dictionary _methodSymbolMap; + + private readonly Dictionary _relocCounts; + + public ObjectInfoBuilder() + { + _nodes = new List(); + _symbols = new List(); + _sections = new List
(); + + _nodeSymbolMap = new Dictionary(); + _methodSymbolMap = new Dictionary(); + + _relocCounts = new Dictionary(); + } + + public void AddNode(ObjectNode node, ISymbolDefinitionNode symbol) + { + _nodes.Add(node); + _nodeSymbolMap.Add(symbol, node); + } + + public void AddRelocation(ObjectNode node, RelocType relocType) + { + node.AddRelocation(); + _relocCounts.TryGetValue(relocType, out int relocTypeCount); + _relocCounts[relocType] = relocTypeCount + 1; + } + + public void AddSymbol(ObjectSymbol symbol) + { + _symbols.Add(symbol); + } + + public void AddSection(Section section) + { + _sections.Add(section); + } + + public void AddMethod(MethodWithGCInfo method, ISymbolDefinitionNode symbol) + { + _methodSymbolMap.Add(symbol, method); + } + + public void Sort() + { + _nodes.Sort(ObjectItem.Comparer.Instance); + _symbols.Sort(ObjectItem.Comparer.Instance); + } + + public bool FindSymbol(ObjectItem item, out int index) + { + index = _symbols.BinarySearch(new ObjectSymbol(item.SectionIndex, item.Offset, name: null), ObjectItem.Comparer.Instance); + bool result = (index >= 0 && index < _symbols.Count && ObjectItem.Comparer.Instance.Compare(_symbols[index], item) == 0); + if (!result) + { + index = -1; + } + return result; + } + + public IEnumerable EnumerateMethods() + { + DebugNameFormatter nameFormatter = new DebugNameFormatter(); + TypeNameFormatter typeNameFormatter = new TypeString(); + HashSet emittedMethods = new HashSet(); + foreach (KeyValuePair symbolMethodPair in _methodSymbolMap) + { + EcmaMethod ecmaMethod = symbolMethodPair.Value.Method.GetTypicalMethodDefinition() as EcmaMethod; + if (ecmaMethod != null && emittedMethods.Add(ecmaMethod)) + { + MethodInfo methodInfo = new MethodInfo(); + methodInfo.MethodToken = (uint)MetadataTokens.GetToken(ecmaMethod.Handle); + methodInfo.AssemblyName = ecmaMethod.Module.Assembly.GetName().Name; + methodInfo.Name = FormatMethodName(symbolMethodPair.Value.Method, typeNameFormatter); + ObjectNode node = _nodeSymbolMap[symbolMethodPair.Key]; + Section section = _sections[node.SectionIndex]; + methodInfo.HotRVA = (uint)(section.RVAWhenPlaced + node.Offset); + methodInfo.HotLength = (uint)node.Length; + methodInfo.ColdRVA = 0; + methodInfo.ColdLength = 0; + yield return methodInfo; + } + } + } + + private string FormatMethodName(MethodDesc method, TypeNameFormatter typeNameFormatter) + { + StringBuilder output = new StringBuilder(); + if (!method.Signature.ReturnType.IsVoid) + { + output.Append(typeNameFormatter.FormatName(method.Signature.ReturnType)); + output.Append(" "); + } + output.Append(typeNameFormatter.FormatName(method.OwningType)); + output.Append("::"); + output.Append(method.Name); + output.Append("("); + for (int paramIndex = 0; paramIndex < method.Signature.Length; paramIndex++) + { + if (paramIndex != 0) + { + output.Append(", "); + } + output.Append(typeNameFormatter.FormatName(method.Signature[paramIndex])); + } + output.Append(")"); + return output.ToString(); + } + + public IReadOnlyList Nodes => _nodes; + public IReadOnlyList
Sections => _sections; + public IReadOnlyList Symbols => _symbols; + + public IReadOnlyDictionary RelocCounts => _relocCounts; + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs index 759fad4ac6fd7..c93d4c188bff5 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs @@ -241,8 +241,8 @@ public void SetWin32Resources(ISymbolNode symbol, int resourcesSize) /// Object data to emit /// Target section /// Textual name of the object data for diagnostic purposese - /// Optional map file builder to output the data item to - public void AddObjectData(ObjectNode.ObjectData objectData, ObjectNodeSection section, string name, MapFileBuilder mapFileBuilder) + /// Optional object info builder to output the data item to + public void AddObjectData(DependencyAnalysis.ObjectNode.ObjectData objectData, ObjectNodeSection section, string name, ObjectInfoBuilder objectInfoBuilder) { if (_written) { @@ -266,7 +266,7 @@ public void AddObjectData(ObjectNode.ObjectData objectData, ObjectNodeSection se throw new NotImplementedException(); } - _sectionBuilder.AddObjectData(objectData, targetSectionIndex, name, mapFileBuilder); + _sectionBuilder.AddObjectData(objectData, targetSectionIndex, name, objectInfoBuilder); } /// @@ -312,10 +312,10 @@ public void Write(Stream outputStream, int? timeDateStamp) /// /// Fill in map builder section table. /// - /// Map file builder to set up - public void AddSections(MapFileBuilder mapFileBuilder) + /// Object info builder to set up + public void AddSections(ObjectInfoBuilder objectInfoBuilder) { - _sectionBuilder.AddSections(mapFileBuilder); + _sectionBuilder.AddSections(objectInfoBuilder); } /// diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs index 7735448376219..db688de1bcb59 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs @@ -437,8 +437,8 @@ private NameMangler GetNameMangler() /// Block to add /// Section index /// Node name to emit in the map file - /// Optional map file to emit - public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, string name, MapFileBuilder mapFileBuilder) + /// Optional output info to collect (used for creating maps and symbols) + public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, string name, ObjectInfoBuilder objectInfoBuilder) { Section section = _sections[sectionIndex]; @@ -475,10 +475,10 @@ public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, st } } - if (mapFileBuilder != null) + if (objectInfoBuilder != null) { - MapFileNode node = new MapFileNode(sectionIndex, alignedOffset, objectData.Data.Length, name); - mapFileBuilder.AddNode(node, objectData.DefinedSymbols[0]); + ObjectNode node = new ObjectNode(sectionIndex, alignedOffset, objectData.Data.Length, name); + objectInfoBuilder.AddNode(node, objectData.DefinedSymbols[0]); if (objectData.Relocs != null) { foreach (Relocation reloc in objectData.Relocs) @@ -486,7 +486,7 @@ public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, st RelocType fileReloc = Relocation.GetFileRelocationType(reloc.RelocType); if (fileReloc != RelocType.IMAGE_REL_BASED_ABSOLUTE) { - mapFileBuilder.AddRelocation(node, fileReloc); + objectInfoBuilder.AddRelocation(node, fileReloc); } } } @@ -498,12 +498,12 @@ public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, st { foreach (ISymbolDefinitionNode symbol in objectData.DefinedSymbols) { - if (mapFileBuilder != null) + if (objectInfoBuilder != null) { Utf8StringBuilder sb = new Utf8StringBuilder(); symbol.AppendMangledName(GetNameMangler(), sb); int sectionRelativeOffset = alignedOffset + symbol.Offset; - mapFileBuilder.AddSymbol(new MapFileSymbol(sectionIndex, sectionRelativeOffset, sb.ToString())); + objectInfoBuilder.AddSymbol(new ObjectSymbol(sectionIndex, sectionRelativeOffset, sb.ToString())); } _symbolMap.Add(symbol, new SymbolTarget( sectionIndex: sectionIndex, @@ -551,11 +551,11 @@ public IEnumerable GetSections() return sectionList; } - public void AddSections(MapFileBuilder mapFileBuilder) + public void AddSections(ObjectInfoBuilder objectInfoBuilder) { foreach (Section section in _sections) { - mapFileBuilder.AddSection(section); + objectInfoBuilder.AddSection(section); } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs new file mode 100644 index 0000000000000..a4f209cbe457d --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using ILCompiler.Diagnostics; + +namespace ILCompiler.PEWriter +{ + public class SymbolFileBuilder + { + private readonly ObjectInfoBuilder _objectInfoBuilder; + + public SymbolFileBuilder(ObjectInfoBuilder objectInfoBuilder) + { + _objectInfoBuilder = objectInfoBuilder; + } + + public void SavePdb(string pdbPath, string dllFileName) + { + Console.WriteLine("Emitting PDB file: {0}", Path.Combine(pdbPath, Path.GetFileNameWithoutExtension(dllFileName) + ".ni.pdb")); + + new PdbWriter(pdbPath, PDBExtraData.None).WritePDBData(dllFileName, _objectInfoBuilder.EnumerateMethods()); + } + + public void SavePerfMap(string perfMapPath, string dllFileName) + { + string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + ".perf.map"); + Console.WriteLine("Emitting PerfMap file: {0}", perfMapFileName); + + PerfMapWriter.Write(perfMapFileName, _objectInfoBuilder.EnumerateMethods()); + } + } +} diff --git a/src/coreclr/tools/aot/crossgen2.sln b/src/coreclr/tools/aot/crossgen2.sln index aa1a8362184dd..cb78b75b95945 100644 --- a/src/coreclr/tools/aot/crossgen2.sln +++ b/src/coreclr/tools/aot/crossgen2.sln @@ -105,12 +105,11 @@ Global {1043373D-8C14-4224-9E2B-75F0DE645E7E}.Release|x64.Build.0 = Release|x64 {1043373D-8C14-4224-9E2B-75F0DE645E7E}.Release|x86.ActiveCfg = Release|Any CPU {1043373D-8C14-4224-9E2B-75F0DE645E7E}.Release|x86.Build.0 = Release|Any CPU - {3EACD929-4725-4173-A845-734936BBDF87}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {3EACD929-4725-4173-A845-734936BBDF87}.Checked|Any CPU.Build.0 = Debug|Any CPU - {3EACD929-4725-4173-A845-734936BBDF87}.Checked|x64.ActiveCfg = Debug|Any CPU - {3EACD929-4725-4173-A845-734936BBDF87}.Checked|x64.Build.0 = Debug|Any CPU - {3EACD929-4725-4173-A845-734936BBDF87}.Checked|x86.ActiveCfg = Debug|Any CPU - {3EACD929-4725-4173-A845-734936BBDF87}.Checked|x86.Build.0 = Debug|Any CPU + {3EACD929-4725-4173-A845-734936BBDF87}.Checked|Any CPU.ActiveCfg = Debug|x86 + {3EACD929-4725-4173-A845-734936BBDF87}.Checked|x64.ActiveCfg = Debug|x64 + {3EACD929-4725-4173-A845-734936BBDF87}.Checked|x64.Build.0 = Debug|x64 + {3EACD929-4725-4173-A845-734936BBDF87}.Checked|x86.ActiveCfg = Debug|x86 + {3EACD929-4725-4173-A845-734936BBDF87}.Checked|x86.Build.0 = Debug|x86 {3EACD929-4725-4173-A845-734936BBDF87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3EACD929-4725-4173-A845-734936BBDF87}.Debug|Any CPU.Build.0 = Debug|Any CPU {3EACD929-4725-4173-A845-734936BBDF87}.Debug|x64.ActiveCfg = Debug|Any CPU diff --git a/src/coreclr/tools/r2rdump/R2RDump.sln b/src/coreclr/tools/r2rdump/R2RDump.sln index 316a22ddc720f..6596a597f104a 100644 --- a/src/coreclr/tools/r2rdump/R2RDump.sln +++ b/src/coreclr/tools/r2rdump/R2RDump.sln @@ -6,7 +6,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "R2RDump", "R2RDump.csproj", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.Reflection.ReadyToRun", "..\aot\ILCompiler.Reflection.ReadyToRun\ILCompiler.Reflection.ReadyToRun.csproj", "{E2A577E5-7AF3-49B3-BA78-7071B75ED64B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILCompiler.Diagnostics", "..\aot\ILCompiler.Diagnostics\ILCompiler.Diagnostics.csproj", "{4E9512BA-F963-472A-B689-37D4D32456F3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.Diagnostics", "..\aot\ILCompiler.Diagnostics\ILCompiler.Diagnostics.csproj", "{4E9512BA-F963-472A-B689-37D4D32456F3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -16,8 +16,8 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|Any CPU.Build.0 = Debug|Any CPU + {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}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -32,10 +32,10 @@ Global {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 - {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|x64.ActiveCfg = Debug|Any CPU - {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|x64.Build.0 = Debug|Any CPU + {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}.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