Optimize HelloWorld usage (#44711)
authorAndrew Au <andrewau@microsoft.com>
Tue, 17 Nov 2020 18:36:47 +0000 (10:36 -0800)
committerGitHub <noreply@github.com>
Tue, 17 Nov 2020 18:36:47 +0000 (10:36 -0800)
src/coreclr/src/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs
src/coreclr/src/tools/r2rdump/R2RDiff.cs
src/coreclr/src/tools/r2rdump/R2RDump.cs
src/coreclr/src/tools/r2rdump/TextDumper.cs

index f0e8431..e2e888c 100644 (file)
@@ -47,6 +47,36 @@ namespace ILCompiler.Reflection.ReadyToRun
         }
     }
 
+    public class ReadyToRunAssembly
+    {
+        private ReadyToRunReader _reader;
+        internal List<string> _availableTypes;
+        internal List<ReadyToRunMethod> _methods;
+
+        internal ReadyToRunAssembly(ReadyToRunReader reader)
+        {
+            _reader = reader;
+        }
+
+        public IReadOnlyList<string> AvailableTypes
+        {
+            get
+            {
+                _reader.EnsureAvailableTypes();
+                return _availableTypes;
+            }
+        }
+
+        public IReadOnlyList<ReadyToRunMethod> Methods
+        {
+            get
+            {
+                _reader.EnsureMethods();
+                return _methods;
+            }
+        }
+    }
+
     public sealed class ReadyToRunReader
     {
         private const string SystemModuleName = "System.Private.CoreLib";
@@ -73,6 +103,7 @@ namespace ILCompiler.Reflection.ReadyToRun
         private int _readyToRunHeaderRVA;
         private ReadyToRunHeader _readyToRunHeader;
         private List<ReadyToRunCoreHeader> _readyToRunAssemblyHeaders;
+        private List<ReadyToRunAssembly> _readyToRunAssemblies;
 
         // DebugInfo
         private Dictionary<int, int> _runtimeFunctionIdToDebugOffset;
@@ -86,16 +117,12 @@ namespace ILCompiler.Reflection.ReadyToRun
         private Dictionary<int, EHInfo> _runtimeFunctionToEHInfo;
 
         // Methods
-        private Dictionary<ReadyToRunSection, List<ReadyToRunMethod>> _methods;
         private List<InstanceMethod> _instanceMethods;
 
         // ImportSections
         private List<ReadyToRunImportSection> _importSections;
         private Dictionary<int, ReadyToRunSignature> _importSignatures;
 
-        // AvailableType
-        private Dictionary<ReadyToRunSection, List<string>> _availableTypes;
-
         // CompilerIdentifier
         private string _compilerIdentifier;
 
@@ -228,15 +255,12 @@ namespace ILCompiler.Reflection.ReadyToRun
             }
         }
 
-        /// <summary>
-        /// The runtime functions and method signatures of each method
-        /// </summary>
-        public Dictionary<ReadyToRunSection, List<ReadyToRunMethod>> Methods
+        public IReadOnlyList<ReadyToRunAssembly> ReadyToRunAssemblies
         {
             get
             {
-                EnsureMethods();
-                return _methods;
+                EnsureHeader();
+                return _readyToRunAssemblies;
             }
         }
 
@@ -253,20 +277,6 @@ namespace ILCompiler.Reflection.ReadyToRun
         }
 
         /// <summary>
-        /// The available types from READYTORUN_SECTION_AVAILABLE_TYPES
-        /// </summary>
-        public Dictionary<ReadyToRunSection, List<string>> AvailableTypes
-        {
-
-            get
-            {
-                EnsureAvailableTypes();
-                return _availableTypes;
-            }
-
-        }
-
-        /// <summary>
         /// The compiler identifier string from READYTORUN_SECTION_COMPILER_IDENTIFIER
         /// </summary>
         public string CompilerIdentifier
@@ -411,14 +421,14 @@ namespace ILCompiler.Reflection.ReadyToRun
             }
         }
 
-        private void EnsureMethods()
+        internal void EnsureMethods()
         {
-            if (_methods != null)
+            EnsureHeader();
+            if (_readyToRunAssemblies[0]._methods != null)
             {
                 return;
             }
 
-            _methods = new Dictionary<ReadyToRunSection, List<ReadyToRunMethod>>();
             _instanceMethods = new List<InstanceMethod>();
 
             if (ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.RuntimeFunctions, out ReadyToRunSection runtimeFunctionSection))
@@ -443,13 +453,10 @@ namespace ILCompiler.Reflection.ReadyToRun
             if (_runtimeFunctionToMethod == null)
             {
                 _runtimeFunctionToMethod = new Dictionary<int, ReadyToRunMethod>();
-                foreach (var section in _methods)
+                foreach (var method in Methods)
                 {
-                    foreach (var method in section.Value)
-                    {
-                        if (!_runtimeFunctionToMethod.ContainsKey(method.EntryPointRuntimeFunctionId))
-                            _runtimeFunctionToMethod.Add(method.EntryPointRuntimeFunctionId, method);
-                    }
+                    if (!_runtimeFunctionToMethod.ContainsKey(method.EntryPointRuntimeFunctionId))
+                        _runtimeFunctionToMethod.Add(method.EntryPointRuntimeFunctionId, method);
                 }
             }
         }
@@ -555,10 +562,15 @@ namespace ILCompiler.Reflection.ReadyToRun
             int r2rHeaderOffset = GetOffset(_readyToRunHeaderRVA);
             _readyToRunHeader = new ReadyToRunHeader(Image, _readyToRunHeaderRVA, r2rHeaderOffset);
 
+            _readyToRunAssemblies = new List<ReadyToRunAssembly>();
             if (_composite)
             {
                 ParseComponentAssemblies();
             }
+            else
+            {
+                _readyToRunAssemblies.Add(new ReadyToRunAssembly(this));
+            }
         }
 
         private void EnsureDebugInfo()
@@ -693,6 +705,8 @@ namespace ILCompiler.Reflection.ReadyToRun
         /// <param name="isEntryPoint">Set to true for each runtime function index representing a method entrypoint</param>
         private void ParseMethodDefEntrypointsSection(ReadyToRunSection section, IAssemblyMetadata componentReader, bool[] isEntryPoint)
         {
+            int assemblyIndex = GetAssemblyIndex(section);
+            _readyToRunAssemblies[assemblyIndex]._methods = new List<ReadyToRunMethod>();
             int methodDefEntryPointsOffset = GetOffset(section.RelativeVirtualAddress);
             NativeArray methodEntryPoints = new NativeArray(Image, (uint)methodDefEntryPointsOffset);
             uint nMethodEntryPoints = methodEntryPoints.GetCount();
@@ -713,12 +727,7 @@ namespace ILCompiler.Reflection.ReadyToRun
                         throw new BadImageFormatException("EntryPointRuntimeFunctionId out of bounds");
                     }
                     isEntryPoint[method.EntryPointRuntimeFunctionId] = true;
-                    if (!_methods.TryGetValue(section, out List<ReadyToRunMethod> sectionMethods))
-                    {
-                        sectionMethods = new List<ReadyToRunMethod>();
-                        _methods.Add(section, sectionMethods);
-                    }
-                    sectionMethods.Add(method);
+                    _readyToRunAssemblies[assemblyIndex]._methods.Add(method);
                 }
             }
         }
@@ -746,7 +755,7 @@ namespace ILCompiler.Reflection.ReadyToRun
                     GetRuntimeFunctionIndexFromOffset(offset, out runtimeFunctionId, out fixupOffset);
                     ReadyToRunMethod r2rMethod = _runtimeFunctionToMethod[runtimeFunctionId];
                     var customMethod = provider.GetMethodFromMethodDef(metadataReader.MetadataReader, MetadataTokens.MethodDefinitionHandle((int)rid), default(TType));
-                    
+
                     if (!Object.ReferenceEquals(customMethod, null) && !foundMethods.ContainsKey(customMethod))
                         foundMethods.Add(customMethod, r2rMethod);
                 }
@@ -865,20 +874,23 @@ namespace ILCompiler.Reflection.ReadyToRun
                 {
                     isEntryPoint[method.EntryPointRuntimeFunctionId] = true;
                 }
-                if (!Methods.TryGetValue(instMethodEntryPointSection, out List<ReadyToRunMethod> sectionMethods))
-                {
-                    sectionMethods = new List<ReadyToRunMethod>();
-                    Methods.Add(instMethodEntryPointSection, sectionMethods);
-                }
-                sectionMethods.Add(method);
                 _instanceMethods.Add(new InstanceMethod(curParser.LowHashcode, method));
                 curParser = allEntriesEnum.GetNext();
             }
         }
 
+        public IEnumerable<ReadyToRunMethod> Methods
+        {
+            get
+            {
+                EnsureMethods();
+                return _readyToRunAssemblies.SelectMany(assembly => assembly.Methods).Concat(_instanceMethods.Select(im => im.Method));
+            }
+        }
+
         private void CountRuntimeFunctions(bool[] isEntryPoint)
         {
-            foreach (ReadyToRunMethod method in Methods.Values.SelectMany(sectionMethods => sectionMethods))
+            foreach (ReadyToRunMethod method in Methods)
             {
                 int runtimeFunctionId = method.EntryPointRuntimeFunctionId;
                 if (runtimeFunctionId == -1)
@@ -895,20 +907,41 @@ namespace ILCompiler.Reflection.ReadyToRun
             }
         }
 
+        public int GetAssemblyIndex(ReadyToRunSection section)
+        {
+            EnsureHeader();
+            if (_composite)
+            {
+                for (int assemblyIndex = 0; assemblyIndex < _readyToRunAssemblyHeaders.Count; assemblyIndex++)
+                {
+                    ReadyToRunSection toMatch;
+                    if (_readyToRunAssemblyHeaders[assemblyIndex].Sections.TryGetValue(section.Type, out toMatch) && section.RelativeVirtualAddress == toMatch.RelativeVirtualAddress)
+                    {
+                        return assemblyIndex;
+                    }
+                }
+                return -1;
+            }
+            else
+            {
+                return 0;
+            }
+        }
+
         /// <summary>
         /// Iterates through a native hashtable to get all RIDs
         /// </summary>
-        private void EnsureAvailableTypes()
+        internal void EnsureAvailableTypes()
         {
-            if (_availableTypes != null)
+            EnsureHeader();
+            if (_readyToRunAssemblies[0]._availableTypes != null)
             {
                 return;
             }
-            _availableTypes = new Dictionary<ReadyToRunSection, List<string>>();
             ReadyToRunSection availableTypesSection;
             if (ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.AvailableTypes, out availableTypesSection))
             {
-                ParseAvailableTypesSection(availableTypesSection, GetGlobalMetadata());
+                ParseAvailableTypesSection(0, availableTypesSection, GetGlobalMetadata());
             }
             else if (_readyToRunAssemblyHeaders != null)
             {
@@ -917,7 +950,7 @@ namespace ILCompiler.Reflection.ReadyToRun
                     if (_readyToRunAssemblyHeaders[assemblyIndex].Sections.TryGetValue(
                         ReadyToRunSectionType.AvailableTypes, out availableTypesSection))
                     {
-                        ParseAvailableTypesSection(availableTypesSection, OpenReferenceAssembly(assemblyIndex + 1));
+                        ParseAvailableTypesSection(assemblyIndex, availableTypesSection, OpenReferenceAssembly(assemblyIndex + 1));
                     }
                 }
             }
@@ -928,8 +961,9 @@ namespace ILCompiler.Reflection.ReadyToRun
         /// as available types are stored separately for each component assembly of the composite R2R executable.
         /// </summary>
         /// <param name="availableTypesSection"></param>
-        private void ParseAvailableTypesSection(ReadyToRunSection availableTypesSection, IAssemblyMetadata metadataReader)
+        private void ParseAvailableTypesSection(int assemblyIndex, ReadyToRunSection availableTypesSection, IAssemblyMetadata metadataReader)
         {
+            _readyToRunAssemblies[assemblyIndex]._availableTypes = new List<string>();
             int availableTypesOffset = GetOffset(availableTypesSection.RelativeVirtualAddress);
             NativeParser parser = new NativeParser(Image, (uint)availableTypesOffset);
             NativeHashtable availableTypes = new NativeHashtable(Image, parser, (uint)(availableTypesOffset + availableTypesSection.Size));
@@ -946,23 +980,14 @@ namespace ILCompiler.Reflection.ReadyToRun
                 {
                     ExportedTypeHandle exportedTypeHandle = MetadataTokens.ExportedTypeHandle((int)rid);
                     string exportedTypeName = GetExportedTypeFullName(metadataReader.MetadataReader, exportedTypeHandle);
-                    if (!AvailableTypes.TryGetValue(availableTypesSection, out List<string> sectionTypes))
-                    {
-                        sectionTypes = new List<string>();
-                        AvailableTypes.Add(availableTypesSection, sectionTypes);
-                    }
-                    sectionTypes.Add("exported " + exportedTypeName);
+
+                    _readyToRunAssemblies[assemblyIndex]._availableTypes.Add("exported " + exportedTypeName);
                 }
                 else
                 {
                     TypeDefinitionHandle typeDefHandle = MetadataTokens.TypeDefinitionHandle((int)rid);
                     string typeDefName = MetadataNameFormatter.FormatHandle(metadataReader.MetadataReader, typeDefHandle);
-                    if (!AvailableTypes.TryGetValue(availableTypesSection, out List<string> sectionTypes))
-                    {
-                        sectionTypes = new List<string>();
-                        AvailableTypes.Add(availableTypesSection, sectionTypes);
-                    }
-                    sectionTypes.Add(typeDefName);
+                    _readyToRunAssemblies[assemblyIndex]._availableTypes.Add(typeDefName);
                 }
 
                 curParser = allEntriesEnum.GetNext();
@@ -1012,6 +1037,7 @@ namespace ILCompiler.Reflection.ReadyToRun
 
                 ReadyToRunCoreHeader assemblyHeader = new ReadyToRunCoreHeader(Image, ref headerOffset);
                 _readyToRunAssemblyHeaders.Add(assemblyHeader);
+                _readyToRunAssemblies.Add(new ReadyToRunAssembly(this));
             }
         }
 
index 25e6dd9..ff660a9 100644 (file)
@@ -90,13 +90,28 @@ namespace R2RDump
             }
         }
 
+        private bool TryGetMethods(ReadyToRunReader reader, ReadyToRunSection section, out IReadOnlyList<ReadyToRunMethod> methods)
+        {
+            int assemblyIndex = reader.GetAssemblyIndex(section);
+            if (assemblyIndex == -1)
+            {
+                methods = null;
+                return false;
+            }
+            else
+            {
+                methods = reader.ReadyToRunAssemblies[assemblyIndex].Methods;
+                return true;
+            }
+        }
+
         private void DiffMethodsForModule(ReadyToRunSection leftSection, ReadyToRunSection rightSection)
         {
-            if (!_leftDumper.Reader.Methods.TryGetValue(leftSection, out List<ReadyToRunMethod> leftSectionMethods))
+            if (!TryGetMethods(_leftDumper.Reader, leftSection, out IReadOnlyList<ReadyToRunMethod> leftSectionMethods))
             {
                 leftSectionMethods = new List<ReadyToRunMethod>();
             }
-            if (!_rightDumper.Reader.Methods.TryGetValue(rightSection, out List<ReadyToRunMethod> rightSectionMethods))
+            if (!TryGetMethods(_rightDumper.Reader, rightSection, out IReadOnlyList<ReadyToRunMethod> rightSectionMethods))
             {
                 rightSectionMethods = new List<ReadyToRunMethod>();
             }
@@ -290,7 +305,7 @@ namespace R2RDump
         {
             Dictionary<string, int> methodMap = new Dictionary<string, int>();
 
-            if (reader.Methods.TryGetValue(section, out List<ReadyToRunMethod> sectionMethods))
+            if (TryGetMethods(reader, section, out IReadOnlyList<ReadyToRunMethod> sectionMethods))
             {
                 foreach (ReadyToRunMethod method in sectionMethods)
                 {
@@ -309,7 +324,7 @@ namespace R2RDump
         /// <param name="signatureFilter">Set of common signatures of methods to dump</param>
         private void DumpCommonMethods(Dumper dumper, ReadyToRunSection section, Dictionary<string, MethodPair> signatureFilter)
         {
-            if (dumper.Reader.Methods.TryGetValue(section, out List<ReadyToRunMethod> sectionMethods))
+            if (!TryGetMethods(dumper.Reader, section, out IReadOnlyList<ReadyToRunMethod> sectionMethods))
             {
                 IEnumerable<ReadyToRunMethod> filteredMethods = sectionMethods
                     .Where(method => signatureFilter.ContainsKey(method.SignatureString))
index fa21ad4..d2909a6 100644 (file)
@@ -176,7 +176,7 @@ namespace R2RDump
 
         public IEnumerable<ReadyToRunMethod> NormalizedMethods()
         {
-            IEnumerable<ReadyToRunMethod> methods = _r2r.Methods.Values.SelectMany(sectionMethods => sectionMethods);
+            IEnumerable<ReadyToRunMethod> methods = _r2r.Methods;
             if (_options.Normalize)
             {
                 methods = methods.OrderBy((m) => m.SignatureString);
@@ -492,7 +492,7 @@ namespace R2RDump
         public IList<ReadyToRunMethod> FindMethod(ReadyToRunReader r2r, string query, bool exact)
         {
             List<ReadyToRunMethod> res = new List<ReadyToRunMethod>();
-            foreach (ReadyToRunMethod method in r2r.Methods.Values.SelectMany(sectionMethods => sectionMethods))
+            foreach (ReadyToRunMethod method in r2r.Methods)
             {
                 if (Match(method, query, exact))
                 {
@@ -529,7 +529,7 @@ namespace R2RDump
         /// <param name="rtfQuery">The name or value to search for</param>
         public RuntimeFunction FindRuntimeFunction(ReadyToRunReader r2r, int rtfQuery)
         {
-            foreach (ReadyToRunMethod m in r2r.Methods.Values.SelectMany(sectionMethods => sectionMethods))
+            foreach (ReadyToRunMethod m in r2r.Methods)
             {
                 foreach (RuntimeFunction rtf in m.RuntimeFunctions)
                 {
index ea60e1d..f03b65e 100644 (file)
@@ -133,7 +133,7 @@ namespace R2RDump
         internal override void DumpAllMethods()
         {
             WriteDivider("R2R Methods");
-            _writer.WriteLine($"{_r2r.Methods.Sum(kvp => kvp.Value.Count)} methods");
+            _writer.WriteLine($"{_r2r.Methods.Count()} methods");
             SkipLine();
             foreach (ReadyToRunMethod method in NormalizedMethods())
             {
@@ -303,10 +303,11 @@ namespace R2RDump
                         _writer.WriteLine(availableTypes.ToString());
                     }
 
-                    if (_r2r.AvailableTypes.TryGetValue(section, out List<string> sectionTypes))
+                    int assemblyIndex1 = _r2r.GetAssemblyIndex(section);
+                    if (assemblyIndex1 != -1)
                     {
                         _writer.WriteLine();
-                        foreach (string name in sectionTypes)
+                        foreach (string name in _r2r.ReadyToRunAssemblies[assemblyIndex1].AvailableTypes)
                         {
                             _writer.WriteLine(name);
                         }
@@ -319,10 +320,11 @@ namespace R2RDump
                         _writer.Write(methodEntryPoints.ToString());
                     }
 
-                    if (_r2r.Methods.TryGetValue(section, out List<ReadyToRunMethod> sectionMethods))
+                    int assemblyIndex2 = _r2r.GetAssemblyIndex(section);
+                    if (assemblyIndex2 != -1)
                     {
                         _writer.WriteLine();
-                        foreach (ReadyToRunMethod method in sectionMethods)
+                        foreach (ReadyToRunMethod method in _r2r.ReadyToRunAssemblies[assemblyIndex2].Methods)
                         {
                             _writer.WriteLine($@"{MetadataTokens.GetToken(method.MethodHandle):X8}: {method.SignatureString}");
                         }