From b01d68f5b9eb52d44c9b29237a545dd6b60e196f Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Sat, 22 Feb 2020 12:25:01 -0800 Subject: [PATCH] Make ReadyToRunReader constructor completely lazy (#32682) --- .../ReadyToRunMethod.cs | 107 ++++++++- .../ReadyToRunReader.cs | 239 +++++++++++---------- 2 files changed, 221 insertions(+), 125 deletions(-) diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs index 2f143b1..c59f99c 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs @@ -11,6 +11,7 @@ using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; using System.Text; +using Internal.Runtime; namespace ILCompiler.Reflection.ReadyToRun { @@ -93,12 +94,12 @@ namespace ILCompiler.Reflection.ReadyToRun /// /// The index of the runtime function /// - public int Id { get; set; } + public int Id { get; } /// /// The relative virtual address to the start of the code block /// - public int StartAddress { get; set; } + public int StartAddress { get; } /// /// The size of the code block in bytes @@ -107,17 +108,17 @@ namespace ILCompiler.Reflection.ReadyToRun /// The EndAddress field in the runtime functions section is conditional on machine type /// Size is -1 for images without the EndAddress field /// - public int Size { get; set; } + public int Size { get; } /// /// The relative virtual address to the unwind info /// - public int UnwindRVA { get; set; } + public int UnwindRVA { get; } /// /// The start offset of the runtime function with is non-zero for methods with multiple runtime functions /// - public int CodeOffset { get; set; } + public int CodeOffset { get; } /// /// The method that this runtime function belongs to @@ -241,7 +242,23 @@ namespace ILCompiler.Reflection.ReadyToRun /// /// All the runtime functions of this method /// - public IList RuntimeFunctions { get; } + public IReadOnlyList RuntimeFunctions + { + get + { + EnsureRuntimeFunctions(); + return _runtimeFunctions; + } + } + + private void EnsureRuntimeFunctions() + { + if (this._runtimeFunctions == null) + { + this._runtimeFunctions = new List(); + this.ParseRuntimeFunctions(); + } + } /// /// The id of the entrypoint runtime function @@ -253,6 +270,7 @@ namespace ILCompiler.Reflection.ReadyToRun private ReadyToRunReader _readyToRunReader; private List _fixupCells; private int? _fixupOffset; + private List _runtimeFunctions; public IReadOnlyList Fixups { @@ -263,6 +281,8 @@ namespace ILCompiler.Reflection.ReadyToRun } } + internal int RuntimeFunctionCount { get; set; } + /// /// Extracts the method signature from the metadata by rid /// @@ -284,7 +304,6 @@ namespace ILCompiler.Reflection.ReadyToRun EntryPointRuntimeFunctionId = entryPointId; MetadataReader = metadataReader; - RuntimeFunctions = new List(); EntityHandle owningTypeHandle; GenericParameterHandleCollection genericParams = default(GenericParameterHandleCollection); @@ -415,5 +434,79 @@ namespace ILCompiler.Reflection.ReadyToRun } // Done with all entries in this table } + + /// + /// Get the RVAs of the runtime functions for each method + /// based on ZapUnwindInfo::Save + /// + private void ParseRuntimeFunctions() + { + int runtimeFunctionId = EntryPointRuntimeFunctionId; + int runtimeFunctionSize = _readyToRunReader.CalculateRuntimeFunctionSize(); + int runtimeFunctionOffset = _readyToRunReader.PEReader.GetOffset(_readyToRunReader.ReadyToRunHeader.Sections[ReadyToRunSectionType.RuntimeFunctions].RelativeVirtualAddress); + int curOffset = runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize; + BaseGcInfo gcInfo = null; + int codeOffset = 0; + for (int i = 0; i < RuntimeFunctionCount; i++) + { + int startRva = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset); + int endRva = -1; + if (_readyToRunReader.Machine == Machine.Amd64) + { + endRva = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset); + } + int unwindRva = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset); + int unwindOffset = _readyToRunReader.PEReader.GetOffset(unwindRva); + + BaseUnwindInfo unwindInfo = null; + if (_readyToRunReader.Machine == Machine.Amd64) + { + unwindInfo = new Amd64.UnwindInfo(_readyToRunReader.Image, unwindOffset); + if (i == 0) + { + gcInfo = new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion); + } + } + else if (_readyToRunReader.Machine == Machine.I386) + { + unwindInfo = new x86.UnwindInfo(_readyToRunReader.Image, unwindOffset); + if (i == 0) + { + gcInfo = new x86.GcInfo(_readyToRunReader.Image, unwindOffset, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion); + } + } + else if (_readyToRunReader.Machine == Machine.ArmThumb2) + { + unwindInfo = new Arm.UnwindInfo(_readyToRunReader.Image, unwindOffset); + if (i == 0) + { + gcInfo = new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion); // Arm and Arm64 use the same GcInfo format as x64 + } + } + else if (_readyToRunReader.Machine == Machine.Arm64) + { + unwindInfo = new Arm64.UnwindInfo(_readyToRunReader.Image, unwindOffset); + if (i == 0) + { + gcInfo = new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion); + } + } + + RuntimeFunction rtf = new RuntimeFunction( + _readyToRunReader, + runtimeFunctionId, + startRva, + endRva, + unwindRva, + codeOffset, + this, + unwindInfo, + gcInfo); + + _runtimeFunctions.Add(rtf); + runtimeFunctionId++; + codeOffset += rtf.Size; + } + } } } 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 d02ed92..01132e3 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.ComponentModel; using System.IO; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -88,6 +87,20 @@ namespace ILCompiler.Reflection.ReadyToRun // ExceptionInfo private Dictionary _runtimeFunctionToEHInfo; + // Methods + private List _methods; + private List _instanceMethods; + + // ImportSections + private List _importSections; + private Dictionary _importCellNames; + + // AvailableType + private List _availableTypes; + + // CompilerIdentifier + private string _compilerIdentifier; + /// /// Underlying PE image reader is used to access raw PE structures like header /// or section list. @@ -199,7 +212,7 @@ namespace ILCompiler.Reflection.ReadyToRun } } - public IList ReaderToRunAssemblyHeaders + public IReadOnlyList ReadyToRunAssemblyHeaders { get { @@ -211,32 +224,77 @@ namespace ILCompiler.Reflection.ReadyToRun /// /// The runtime functions and method signatures of each method /// - public IList Methods { get; private set; } + public IReadOnlyList Methods + { + get + { + EnsureMethods(); + return _methods; + } + } /// /// Parsed instance entrypoint table entries. /// - public IList InstanceMethods { get; private set; } + public IReadOnlyList InstanceMethods + { + get + { + EnsureMethods(); + return _instanceMethods; + } + } /// /// The available types from READYTORUN_SECTION_AVAILABLE_TYPES /// - public IList AvailableTypes { get; private set; } + public IReadOnlyList AvailableTypes + { + + get + { + EnsureAvailableTypes(); + return _availableTypes; + } + + } /// /// The compiler identifier string from READYTORUN_SECTION_COMPILER_IDENTIFIER /// - public string CompilerIdentifier { get; private set; } + public string CompilerIdentifier + { + get + { + EnsureCompilerIdentifier(); + return _compilerIdentifier; + } + } /// /// List of import sections present in the R2R executable. /// - public IList ImportSections { get; private set; } + public IReadOnlyList ImportSections + { + get + { + EnsureImportSections(); + return _importSections; + } + } /// /// Map from import cell addresses to their symbolic names. /// - public Dictionary ImportCellNames { get; private set; } + public IReadOnlyDictionary ImportCellNames + { + get + { + EnsureImportSections(); + return _importCellNames; + } + + } internal Dictionary RuntimeFunctionToDebugInfo { @@ -336,39 +394,28 @@ namespace ILCompiler.Reflection.ReadyToRun ImmutableArray content = PEReader.GetEntireImage().GetContent(); Image = Unsafe.As, byte[]>(ref content); + } - if (_composite) + private void EnsureMethods() + { + if (_methods != null) { - ParseComponentAssemblies(); + return; } - - // This is a work in progress toward lazy initialization. - // Ideally, here should be the end of the Initialize() method - - ImportSections = new List(); - ImportCellNames = new Dictionary(); - ParseImportSections(); - - Methods = new List(); - InstanceMethods = new List(); + _methods = new List(); + _instanceMethods = new List(); if (ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.RuntimeFunctions, out ReadyToRunSection runtimeFunctionSection)) { int runtimeFunctionSize = CalculateRuntimeFunctionSize(); uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize); - int runtimeFunctionOffset = PEReader.GetOffset(runtimeFunctionSection.RelativeVirtualAddress); bool[] isEntryPoint = new bool[nRuntimeFunctions]; // initialize R2RMethods ParseMethodDefEntrypoints(isEntryPoint); ParseInstanceMethodEntrypoints(isEntryPoint); - ParseRuntimeFunctions(isEntryPoint, runtimeFunctionOffset); + CountRuntimeFunctions(isEntryPoint); } - - AvailableTypes = new List(); - ParseAvailableTypes(); - - CompilerIdentifier = ParseCompilerIdentifier(); } private bool TryLocateNativeReadyToRunHeader() @@ -453,6 +500,11 @@ namespace ILCompiler.Reflection.ReadyToRun Debug.Assert(_readyToRunHeaderRVA != 0); int r2rHeaderOffset = GetOffset(_readyToRunHeaderRVA); _readyToRunHeader = new ReadyToRunHeader(Image, _readyToRunHeaderRVA, r2rHeaderOffset); + + if (_composite) + { + ParseComponentAssemblies(); + } } private void EnsureDebugInfo() @@ -547,7 +599,7 @@ namespace ILCompiler.Reflection.ReadyToRun /// /// Each runtime function entry has 3 fields for Amd64 machines (StartAddress, EndAddress, UnwindRVA), otherwise 2 fields (StartAddress, UnwindRVA) /// - private int CalculateRuntimeFunctionSize() + internal int CalculateRuntimeFunctionSize() { if (Machine == Machine.Amd64) { @@ -566,11 +618,11 @@ namespace ILCompiler.Reflection.ReadyToRun { ParseMethodDefEntrypointsSection(methodEntryPointSection, GetGlobalMetadataReader(), isEntryPoint); } - else if (_readyToRunAssemblyHeaders != null) + else if (ReadyToRunAssemblyHeaders != null) { - for (int assemblyIndex = 0; assemblyIndex < _readyToRunAssemblyHeaders.Count; assemblyIndex++) + for (int assemblyIndex = 0; assemblyIndex < ReadyToRunAssemblyHeaders.Count; assemblyIndex++) { - if (_readyToRunAssemblyHeaders[assemblyIndex].Sections.TryGetValue(ReadyToRunSectionType.MethodDefEntryPoints, out methodEntryPointSection)) + if (ReadyToRunAssemblyHeaders[assemblyIndex].Sections.TryGetValue(ReadyToRunSectionType.MethodDefEntryPoints, out methodEntryPointSection)) { ParseMethodDefEntrypointsSection(methodEntryPointSection, OpenReferenceAssembly(assemblyIndex + 2), isEntryPoint); } @@ -600,14 +652,14 @@ namespace ILCompiler.Reflection.ReadyToRun int runtimeFunctionId; int? fixupOffset; GetRuntimeFunctionIndexFromOffset(offset, out runtimeFunctionId, out fixupOffset); - ReadyToRunMethod method = new ReadyToRunMethod(this, Methods.Count, metadataReader, methodHandle, runtimeFunctionId, owningType: null, constrainedType: null, instanceArgs: null, fixupOffset: fixupOffset); + ReadyToRunMethod method = new ReadyToRunMethod(this, _methods.Count, metadataReader, methodHandle, runtimeFunctionId, owningType: null, constrainedType: null, instanceArgs: null, fixupOffset: fixupOffset); if (method.EntryPointRuntimeFunctionId < 0 || method.EntryPointRuntimeFunctionId >= isEntryPoint.Length) { throw new BadImageFormatException("EntryPointRuntimeFunctionId out of bounds"); } isEntryPoint[method.EntryPointRuntimeFunctionId] = true; - Methods.Add(method); + _methods.Add(method); } } } @@ -680,7 +732,7 @@ namespace ILCompiler.Reflection.ReadyToRun GetRuntimeFunctionIndexFromOffset((int)decoder.Offset, out runtimeFunctionId, out fixupOffset); ReadyToRunMethod method = new ReadyToRunMethod( this, - Methods.Count, + _methods.Count, mdReader, methodHandle, runtimeFunctionId, @@ -692,100 +744,41 @@ namespace ILCompiler.Reflection.ReadyToRun { isEntryPoint[method.EntryPointRuntimeFunctionId] = true; } - Methods.Add(method); - InstanceMethods.Add(new InstanceMethod(curParser.LowHashcode, method)); + _methods.Add(method); + _instanceMethods.Add(new InstanceMethod(curParser.LowHashcode, method)); curParser = allEntriesEnum.GetNext(); } } - /// - /// Get the RVAs of the runtime functions for each method - /// based on ZapUnwindInfo::Save - /// - private void ParseRuntimeFunctions(bool[] isEntryPoint, int runtimeFunctionOffset) + private void CountRuntimeFunctions(bool[] isEntryPoint) { - foreach (ReadyToRunMethod method in Methods) + foreach (ReadyToRunMethod method in _methods) { int runtimeFunctionId = method.EntryPointRuntimeFunctionId; if (runtimeFunctionId == -1) continue; - int runtimeFunctionSize = CalculateRuntimeFunctionSize(); - ParseRuntimeFunctionsForMethod(isEntryPoint, runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize, method, runtimeFunctionId); - } - } - - private void ParseRuntimeFunctionsForMethod(bool[] isEntryPoint, int curOffset, ReadyToRunMethod method, int runtimeFunctionId) - { - BaseGcInfo gcInfo = null; - int codeOffset = 0; - do - { - int startRva = NativeReader.ReadInt32(Image, ref curOffset); - int endRva = -1; - if (Machine == Machine.Amd64) - { - endRva = NativeReader.ReadInt32(Image, ref curOffset); - } - int unwindRva = NativeReader.ReadInt32(Image, ref curOffset); - int unwindOffset = GetOffset(unwindRva); - BaseUnwindInfo unwindInfo = null; - if (Machine == Machine.Amd64) - { - unwindInfo = new Amd64.UnwindInfo(Image, unwindOffset); - if (isEntryPoint[runtimeFunctionId]) - { - gcInfo = new Amd64.GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, ReadyToRunHeader.MajorVersion); - } - } - else if (Machine == Machine.I386) - { - unwindInfo = new x86.UnwindInfo(Image, unwindOffset); - if (isEntryPoint[runtimeFunctionId]) - { - gcInfo = new x86.GcInfo(Image, unwindOffset, Machine, ReadyToRunHeader.MajorVersion); - } - } - else if (Machine == Machine.ArmThumb2) - { - unwindInfo = new Arm.UnwindInfo(Image, unwindOffset); - if (isEntryPoint[runtimeFunctionId]) - { - gcInfo = new Amd64.GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, ReadyToRunHeader.MajorVersion); // Arm and Arm64 use the same GcInfo format as x64 - } - } - else if (Machine == Machine.Arm64) + int count = 0; + int i = runtimeFunctionId; + do { - unwindInfo = new Arm64.UnwindInfo(Image, unwindOffset); - if (isEntryPoint[runtimeFunctionId]) - { - gcInfo = new Amd64.GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, ReadyToRunHeader.MajorVersion); - } - } - - RuntimeFunction rtf = new RuntimeFunction( - this, - runtimeFunctionId, - startRva, - endRva, - unwindRva, - codeOffset, - method, - unwindInfo, - gcInfo); - - method.RuntimeFunctions.Add(rtf); - runtimeFunctionId++; - codeOffset += rtf.Size; + count++; + i++; + } while (i < isEntryPoint.Length && !isEntryPoint[i]); + method.RuntimeFunctionCount = count; } - while (runtimeFunctionId < isEntryPoint.Length && !isEntryPoint[runtimeFunctionId]); } /// /// Iterates through a native hashtable to get all RIDs /// - private void ParseAvailableTypes() + private void EnsureAvailableTypes() { + if (_availableTypes != null) + { + return; + } + _availableTypes = new List(); ReadyToRunSection availableTypesSection; if (ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.AvailableTypes, out availableTypesSection)) { @@ -827,13 +820,13 @@ namespace ILCompiler.Reflection.ReadyToRun { ExportedTypeHandle exportedTypeHandle = MetadataTokens.ExportedTypeHandle((int)rid); string exportedTypeName = GetExportedTypeFullName(metadataReader, exportedTypeHandle); - AvailableTypes.Add("exported " + exportedTypeName); + _availableTypes.Add("exported " + exportedTypeName); } else { TypeDefinitionHandle typeDefHandle = MetadataTokens.TypeDefinitionHandle((int)rid); string typeDefName = MetadataNameFormatter.FormatHandle(metadataReader, typeDefHandle); - AvailableTypes.Add(typeDefName); + _availableTypes.Add(typeDefName); } curParser = allEntriesEnum.GetNext(); @@ -843,16 +836,20 @@ namespace ILCompiler.Reflection.ReadyToRun /// /// Converts the bytes in the compiler identifier section to characters in a string /// - private string ParseCompilerIdentifier() + private void EnsureCompilerIdentifier() { + if (_compilerIdentifier != null) + { + return; + } if (!ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.CompilerIdentifier, out ReadyToRunSection compilerIdentifierSection)) { - return ""; + return; } byte[] identifier = new byte[compilerIdentifierSection.Size - 1]; int identifierOffset = GetOffset(compilerIdentifierSection.RelativeVirtualAddress); Array.Copy(Image, identifierOffset, identifier, 0, compilerIdentifierSection.Size - 1); - return Encoding.UTF8.GetString(identifier); + _compilerIdentifier = Encoding.UTF8.GetString(identifier); } /// @@ -885,8 +882,14 @@ namespace ILCompiler.Reflection.ReadyToRun /// /// based on ZapImportSectionsTable::Save /// - private void ParseImportSections() + private void EnsureImportSections() { + if (_importSections != null) + { + return; + } + _importSections = new List(); + _importCellNames = new Dictionary(); if (!ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.ImportSections, out ReadyToRunSection importSectionsSection)) { return; @@ -941,7 +944,7 @@ namespace ILCompiler.Reflection.ReadyToRun int sigOffset = GetOffset((int)sigRva); string cellName = MetadataNameFormatter.FormatSignature(_assemblyResolver, this, sigOffset); entries.Add(new ReadyToRunImportSection.ImportSectionEntry(entries.Count, entryOffset, entryOffset + rva, section, sigRva, cellName)); - ImportCellNames.Add(rva + entrySize * i, cellName); + _importCellNames.Add(rva + entrySize * i, cellName); } int auxDataRVA = NativeReader.ReadInt32(Image, ref offset); @@ -950,7 +953,7 @@ namespace ILCompiler.Reflection.ReadyToRun { auxDataOffset = GetOffset(auxDataRVA); } - ImportSections.Add(new ReadyToRunImportSection(ImportSections.Count, this, rva, size, flags, type, entrySize, signatureRVA, entries, auxDataRVA, auxDataOffset, Machine, ReadyToRunHeader.MajorVersion)); + _importSections.Add(new ReadyToRunImportSection(_importSections.Count, this, rva, size, flags, type, entrySize, signatureRVA, entries, auxDataRVA, auxDataOffset, Machine, ReadyToRunHeader.MajorVersion)); } } -- 2.7.4