From: Tomáš Rylek Date: Tue, 25 Feb 2020 08:55:31 +0000 (+0100) Subject: R2RDump improvements in composite format support (#32499) X-Git-Tag: submit/tizen/20210909.063632~9515 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=67580dcf025222985ddaacc6c22ebec8c7f9a707;p=platform%2Fupstream%2Fdotnet%2Fruntime.git R2RDump improvements in composite format support (#32499) 1) Added back-translation table from component assembly names to their indices; 2) Added clean split of available types and method entrypoints per component module and modified the various dumps as appropriate; 3) Added dump of component header sections for composite files. Thanks Tomas --- diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs index 01132e3..983a624 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs @@ -18,6 +18,7 @@ using Internal.Runtime; using Internal.ReadyToRunConstants; using Debug = System.Diagnostics.Debug; +using System.Linq; namespace ILCompiler.Reflection.ReadyToRun { @@ -83,12 +84,13 @@ namespace ILCompiler.Reflection.ReadyToRun // ManifestReferences private MetadataReader _manifestReader; private List _manifestReferences; + private Dictionary _manifestReferenceAssemblies; // ExceptionInfo private Dictionary _runtimeFunctionToEHInfo; // Methods - private List _methods; + private Dictionary> _methods; private List _instanceMethods; // ImportSections @@ -96,7 +98,7 @@ namespace ILCompiler.Reflection.ReadyToRun private Dictionary _importCellNames; // AvailableType - private List _availableTypes; + private Dictionary> _availableTypes; // CompilerIdentifier private string _compilerIdentifier; @@ -127,15 +129,12 @@ namespace ILCompiler.Reflection.ReadyToRun /// The list originates in the top-level R2R image and is copied /// to all reference assemblies for the sake of simplicity. /// - public IEnumerable ManifestReferenceAssemblies + public Dictionary ManifestReferenceAssemblies { get { - // TODO (refactoring) make this a IReadOnlyList to be consistent with the rest of the interface - foreach (AssemblyReferenceHandle manifestReference in ManifestReferences) - { - yield return ManifestReader.GetString(ManifestReader.GetAssemblyReference(manifestReference).Name); - } + EnsureManifestReferenceAssemblies(); + return _manifestReferenceAssemblies; } } @@ -224,7 +223,7 @@ namespace ILCompiler.Reflection.ReadyToRun /// /// The runtime functions and method signatures of each method /// - public IReadOnlyList Methods + public Dictionary> Methods { get { @@ -248,7 +247,7 @@ namespace ILCompiler.Reflection.ReadyToRun /// /// The available types from READYTORUN_SECTION_AVAILABLE_TYPES /// - public IReadOnlyList AvailableTypes + public Dictionary> AvailableTypes { get @@ -402,7 +401,8 @@ namespace ILCompiler.Reflection.ReadyToRun { return; } - _methods = new List(); + + _methods = new Dictionary>(); _instanceMethods = new List(); if (ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.RuntimeFunctions, out ReadyToRunSection runtimeFunctionSection)) @@ -557,6 +557,21 @@ namespace ILCompiler.Reflection.ReadyToRun } } + private void EnsureManifestReferenceAssemblies() + { + if (_manifestReferenceAssemblies != null) + { + return; + } + EnsureManifestReferences(); + _manifestReferenceAssemblies = new Dictionary(_manifestReferences.Count); + for (int assemblyIndex = 0; assemblyIndex < _manifestReferences.Count; assemblyIndex++) + { + string assemblyName = ManifestReader.GetString(ManifestReader.GetAssemblyReference(_manifestReferences[assemblyIndex]).Name); + _manifestReferenceAssemblies.Add(assemblyName, assemblyIndex); + } + } + private unsafe void EnsureExceptionInfo() { if (_runtimeFunctionToEHInfo != null) @@ -659,7 +674,12 @@ namespace ILCompiler.Reflection.ReadyToRun throw new BadImageFormatException("EntryPointRuntimeFunctionId out of bounds"); } isEntryPoint[method.EntryPointRuntimeFunctionId] = true; - _methods.Add(method); + if (!_methods.TryGetValue(section, out List sectionMethods)) + { + sectionMethods = new List(); + _methods.Add(section, sectionMethods); + } + sectionMethods.Add(method); } } } @@ -744,7 +764,12 @@ namespace ILCompiler.Reflection.ReadyToRun { isEntryPoint[method.EntryPointRuntimeFunctionId] = true; } - _methods.Add(method); + if (!Methods.TryGetValue(instMethodEntryPointSection, out List sectionMethods)) + { + sectionMethods = new List(); + Methods.Add(instMethodEntryPointSection, sectionMethods); + } + sectionMethods.Add(method); _instanceMethods.Add(new InstanceMethod(curParser.LowHashcode, method)); curParser = allEntriesEnum.GetNext(); } @@ -752,7 +777,7 @@ namespace ILCompiler.Reflection.ReadyToRun private void CountRuntimeFunctions(bool[] isEntryPoint) { - foreach (ReadyToRunMethod method in _methods) + foreach (ReadyToRunMethod method in Methods.Values.SelectMany(sectionMethods => sectionMethods)) { int runtimeFunctionId = method.EntryPointRuntimeFunctionId; if (runtimeFunctionId == -1) @@ -778,7 +803,7 @@ namespace ILCompiler.Reflection.ReadyToRun { return; } - _availableTypes = new List(); + _availableTypes = new Dictionary>(); ReadyToRunSection availableTypesSection; if (ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.AvailableTypes, out availableTypesSection)) { @@ -820,13 +845,23 @@ namespace ILCompiler.Reflection.ReadyToRun { ExportedTypeHandle exportedTypeHandle = MetadataTokens.ExportedTypeHandle((int)rid); string exportedTypeName = GetExportedTypeFullName(metadataReader, exportedTypeHandle); - _availableTypes.Add("exported " + exportedTypeName); + if (!AvailableTypes.TryGetValue(availableTypesSection, out List sectionTypes)) + { + sectionTypes = new List(); + AvailableTypes.Add(availableTypesSection, sectionTypes); + } + sectionTypes.Add("exported " + exportedTypeName); } else { TypeDefinitionHandle typeDefHandle = MetadataTokens.TypeDefinitionHandle((int)rid); string typeDefName = MetadataNameFormatter.FormatHandle(metadataReader, typeDefHandle); - _availableTypes.Add(typeDefName); + if (!AvailableTypes.TryGetValue(availableTypesSection, out List sectionTypes)) + { + sectionTypes = new List(); + AvailableTypes.Add(availableTypesSection, sectionTypes); + } + sectionTypes.Add(typeDefName); } curParser = allEntriesEnum.GetNext(); diff --git a/src/coreclr/src/tools/r2rdump/R2RDiff.cs b/src/coreclr/src/tools/r2rdump/R2RDiff.cs index 8a7021b..e1134bb 100644 --- a/src/coreclr/src/tools/r2rdump/R2RDiff.cs +++ b/src/coreclr/src/tools/r2rdump/R2RDiff.cs @@ -57,9 +57,54 @@ namespace R2RDump DiffR2RSections(); DiffR2RMethods(); - Dictionary leftMethods = new Dictionary(_leftDumper.Reader.Methods + if (!_leftDumper.Reader.ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.MethodDefEntryPoints, out ReadyToRunSection leftSection)) + { + leftSection = new ReadyToRunSection(); + } + if (!_rightDumper.Reader.ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.MethodDefEntryPoints, out ReadyToRunSection rightSection)) + { + rightSection = new ReadyToRunSection(); + } + + DiffMethodsForModule(leftSection, rightSection); + + if (_leftDumper.Reader.Composite && _rightDumper.Reader.Composite) + { + HashSet allComponentAssemblies = new HashSet(_leftDumper.Reader.ManifestReferenceAssemblies.Keys); + allComponentAssemblies.UnionWith(_rightDumper.Reader.ManifestReferenceAssemblies.Keys); + foreach (string assemblyName in allComponentAssemblies.OrderBy(name => name)) + { + int leftIndex = _leftDumper.Reader.ManifestReferenceAssemblies[assemblyName]; + int rightIndex = _rightDumper.Reader.ManifestReferenceAssemblies[assemblyName]; + + if (leftIndex < 0 || !_leftDumper.Reader.ReadyToRunAssemblyHeaders[leftIndex].Sections.TryGetValue(ReadyToRunSectionType.MethodDefEntryPoints, out leftSection)) + { + leftSection = new ReadyToRunSection(); + } + if (rightIndex < 0 || !_rightDumper.Reader.ReadyToRunAssemblyHeaders[rightIndex].Sections.TryGetValue(ReadyToRunSectionType.MethodDefEntryPoints, out rightSection)) + { + rightSection = new ReadyToRunSection(); + } + _writer.WriteLine($@"{assemblyName}: component method diff"); + DiffMethodsForModule(leftSection, rightSection); + } + } + } + + private void DiffMethodsForModule(ReadyToRunSection leftSection, ReadyToRunSection rightSection) + { + if (!_leftDumper.Reader.Methods.TryGetValue(leftSection, out List leftSectionMethods)) + { + leftSectionMethods = new List(); + } + if (!_rightDumper.Reader.Methods.TryGetValue(leftSection, out List rightSectionMethods)) + { + rightSectionMethods = new List(); + } + + Dictionary leftMethods = new Dictionary(leftSectionMethods .Select(method => new KeyValuePair(method.SignatureString, method))); - Dictionary rightMethods = new Dictionary(_rightDumper.Reader.Methods + Dictionary rightMethods = new Dictionary(rightSectionMethods .Select(method => new KeyValuePair(method.SignatureString, method))); Dictionary commonMethods = new Dictionary(leftMethods .Select(kvp => new KeyValuePair(kvp.Key, @@ -69,8 +114,8 @@ namespace R2RDump { commonMethods = new Dictionary(HideMethodsWithSameDisassembly(commonMethods)); } - DumpCommonMethods(_leftDumper, commonMethods); - DumpCommonMethods(_rightDumper, commonMethods); + DumpCommonMethods(_leftDumper, leftSection, commonMethods); + DumpCommonMethods(_rightDumper, rightSection, commonMethods); } /// @@ -104,7 +149,40 @@ namespace R2RDump /// private void DiffR2RMethods() { - ShowDiff(GetR2RMethodMap(_leftDumper.Reader), GetR2RMethodMap(_rightDumper.Reader), "R2R methods"); + DiffR2RMethodsForHeader(_leftDumper.Reader.ReadyToRunHeader, _rightDumper.Reader.ReadyToRunHeader); + } + + private void DiffR2RMethodsForHeader(ReadyToRunCoreHeader leftHeader, ReadyToRunCoreHeader rightHeader) + { + if (!leftHeader.Sections.TryGetValue(ReadyToRunSectionType.MethodDefEntryPoints, out ReadyToRunSection leftSection)) + { + leftSection = new ReadyToRunSection(); + } + if (!rightHeader.Sections.TryGetValue(ReadyToRunSectionType.MethodDefEntryPoints, out ReadyToRunSection rightSection)) + { + rightSection = new ReadyToRunSection(); + } + ShowDiff(GetR2RMethodMap(_leftDumper.Reader, leftSection), GetR2RMethodMap(_rightDumper.Reader, rightSection), "R2R methods"); + + if (_leftDumper.Reader.Composite && _rightDumper.Reader.Composite) + { + HashSet allComponentAssemblies = new HashSet(_leftDumper.Reader.ManifestReferenceAssemblies.Keys); + allComponentAssemblies.UnionWith(_rightDumper.Reader.ManifestReferenceAssemblies.Keys); + foreach (string assemblyName in allComponentAssemblies.OrderBy(name => name)) + { + int leftIndex = _leftDumper.Reader.ManifestReferenceAssemblies[assemblyName]; + int rightIndex = _rightDumper.Reader.ManifestReferenceAssemblies[assemblyName]; + if (leftIndex < 0 || !_leftDumper.Reader.ReadyToRunAssemblyHeaders[leftIndex].Sections.TryGetValue(ReadyToRunSectionType.MethodDefEntryPoints, out leftSection)) + { + leftSection = new ReadyToRunSection(); + } + if (rightIndex < 0 || !_rightDumper.Reader.ReadyToRunAssemblyHeaders[rightIndex].Sections.TryGetValue(ReadyToRunSectionType.MethodDefEntryPoints, out rightSection)) + { + rightSection = new ReadyToRunSection(); + } + ShowDiff(GetR2RMethodMap(_leftDumper.Reader, leftSection), GetR2RMethodMap(_rightDumper.Reader, rightSection), $"{assemblyName}: component R2R methods"); + } + } } /// @@ -209,14 +287,17 @@ namespace R2RDump /// /// R2R image to scan /// - private Dictionary GetR2RMethodMap(ReadyToRunReader reader) + private Dictionary GetR2RMethodMap(ReadyToRunReader reader, ReadyToRunSection section) { Dictionary methodMap = new Dictionary(); - foreach (ReadyToRunMethod method in reader.Methods) + if (reader.Methods.TryGetValue(section, out List sectionMethods)) { - int size = method.RuntimeFunctions.Sum(rf => rf.Size); - methodMap.Add(method.SignatureString, size); + foreach (ReadyToRunMethod method in sectionMethods) + { + int size = method.RuntimeFunctions.Sum(rf => rf.Size); + methodMap.Add(method.SignatureString, size); + } } return methodMap; @@ -227,17 +308,18 @@ namespace R2RDump /// /// Output dumper to use /// Set of common signatures of methods to dump - private void DumpCommonMethods(Dumper dumper, Dictionary signatureFilter) + private void DumpCommonMethods(Dumper dumper, ReadyToRunSection section, Dictionary signatureFilter) { - IEnumerable filteredMethods = dumper - .Reader - .Methods - .Where(method => signatureFilter.ContainsKey(method.SignatureString)) - .OrderBy(method => method.SignatureString); - - foreach (ReadyToRunMethod method in filteredMethods) + if (dumper.Reader.Methods.TryGetValue(section, out List sectionMethods)) { - dumper.DumpMethod(method); + IEnumerable filteredMethods = sectionMethods + .Where(method => signatureFilter.ContainsKey(method.SignatureString)) + .OrderBy(method => method.SignatureString); + + foreach (ReadyToRunMethod method in filteredMethods) + { + dumper.DumpMethod(method); + } } } diff --git a/src/coreclr/src/tools/r2rdump/R2RDump.cs b/src/coreclr/src/tools/r2rdump/R2RDump.cs index ce459a5..b874fa6 100644 --- a/src/coreclr/src/tools/r2rdump/R2RDump.cs +++ b/src/coreclr/src/tools/r2rdump/R2RDump.cs @@ -142,9 +142,9 @@ namespace R2RDump _options = options; } - public IEnumerable NormalizedSections() + public IEnumerable NormalizedSections(ReadyToRunCoreHeader header) { - IEnumerable sections = _r2r.ReadyToRunHeader.Sections.Values; + IEnumerable sections = header.Sections.Values; if (_options.Normalize) { sections = sections.OrderBy((s) => s.Type); @@ -154,7 +154,7 @@ namespace R2RDump public IEnumerable NormalizedMethods() { - IEnumerable methods = _r2r.Methods; + IEnumerable methods = _r2r.Methods.Values.SelectMany(sectionMethods => sectionMethods); if (_options.Normalize) { methods = methods.OrderBy((m) => m.SignatureString); @@ -441,7 +441,7 @@ namespace R2RDump public IList FindMethod(ReadyToRunReader r2r, string query, bool exact) { List res = new List(); - foreach (ReadyToRunMethod method in r2r.Methods) + foreach (ReadyToRunMethod method in r2r.Methods.Values.SelectMany(sectionMethods => sectionMethods)) { if (Match(method, query, exact)) { @@ -478,7 +478,7 @@ namespace R2RDump /// The name or value to search for public RuntimeFunction FindRuntimeFunction(ReadyToRunReader r2r, int rtfQuery) { - foreach (ReadyToRunMethod m in r2r.Methods) + foreach (ReadyToRunMethod m in r2r.Methods.Values.SelectMany(sectionMethods => sectionMethods)) { foreach (RuntimeFunction rtf in m.RuntimeFunctions) { diff --git a/src/coreclr/src/tools/r2rdump/TextDumper.cs b/src/coreclr/src/tools/r2rdump/TextDumper.cs index b5610d7..1b3cf27 100644 --- a/src/coreclr/src/tools/r2rdump/TextDumper.cs +++ b/src/coreclr/src/tools/r2rdump/TextDumper.cs @@ -43,8 +43,8 @@ namespace R2RDump internal override void WriteDivider(string title) { - int len = 61 - title.Length - 2; - _writer.WriteLine(new String('=', len / 2) + " " + title + " " + new String('=', (int)Math.Ceiling(len / 2.0))); + int len = Math.Max(61 - title.Length - 2, 2); + _writer.WriteLine(new String('=', len / 2) + " " + title + " " + new String('=', (len + 1) / 2)); SkipLine(); } @@ -77,10 +77,27 @@ namespace R2RDump _writer.WriteLine($"{_r2r.ReadyToRunHeader.Sections.Count} sections"); SkipLine(); - foreach (ReadyToRunSection section in NormalizedSections()) + foreach (ReadyToRunSection section in NormalizedSections(_r2r.ReadyToRunHeader)) { DumpSection(section); } + + if (_r2r.Composite) + { + WriteDivider("Component Assembly Sections"); + int assemblyIndex = 0; + foreach (string assemblyName in _r2r.ManifestReferenceAssemblies.OrderBy(kvp => kvp.Value).Select(kvp => kvp.Key)) + { + WriteDivider($@"Component Assembly [{assemblyIndex}]: {assemblyName}"); + ReadyToRunCoreHeader assemblyHeader = _r2r.ReadyToRunAssemblyHeaders[assemblyIndex]; + foreach (ReadyToRunSection section in NormalizedSections(assemblyHeader)) + { + DumpSection(section); + } + assemblyIndex++; + } + + } } SkipLine(); } @@ -289,9 +306,13 @@ namespace R2RDump _writer.WriteLine(availableTypes.ToString()); } - foreach (string name in _r2r.AvailableTypes) + if (_r2r.AvailableTypes.TryGetValue(section, out List sectionTypes)) { - _writer.WriteLine(name); + _writer.WriteLine(); + foreach (string name in sectionTypes) + { + _writer.WriteLine(name); + } } break; case ReadyToRunSectionType.MethodDefEntryPoints: @@ -300,6 +321,15 @@ namespace R2RDump NativeArray methodEntryPoints = new NativeArray(_r2r.Image, (uint)_r2r.GetOffset(section.RelativeVirtualAddress)); _writer.Write(methodEntryPoints.ToString()); } + + if (_r2r.Methods.TryGetValue(section, out List sectionMethods)) + { + _writer.WriteLine(); + foreach (ReadyToRunMethod method in sectionMethods) + { + _writer.WriteLine($@"{MetadataTokens.GetToken(method.MethodHandle):X8}: {method.SignatureString}"); + } + } break; case ReadyToRunSectionType.InstanceMethodEntryPoints: if (!_options.Naked) @@ -391,9 +421,9 @@ namespace R2RDump } } - _writer.WriteLine($"Manifest metadata AssemblyRef's ({_r2r.ManifestReferenceAssemblies.Count()} entries):"); + _writer.WriteLine($"Manifest metadata AssemblyRef's ({_r2r.ManifestReferenceAssemblies.Count} entries):"); int manifestAsmIndex = 0; - foreach (string manifestReferenceAssembly in _r2r.ManifestReferenceAssemblies) + foreach (string manifestReferenceAssembly in _r2r.ManifestReferenceAssemblies.OrderBy(kvp => kvp.Value).Select(kvp => kvp.Key)) { _writer.WriteLine($"[ID 0x{manifestAsmIndex + assemblyRefCount + 2:X2}]: {manifestReferenceAssembly}"); manifestAsmIndex++;