| File: Compiler\MstatObjectDumper.cs | Web Access |
| Project: src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler) |
// 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.Collections.Immutable; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using ILCompiler.DependencyAnalysis; using ILCompiler.DependencyAnalysisFramework; using Debug = System.Diagnostics.Debug; using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData; namespace ILCompiler { public class MstatObjectDumper : ObjectDumper { private const int VersionMajor = 2; private const int VersionMinor = 2; private readonly string _fileName; private readonly MstatEmitter _emitter; private readonly InstructionEncoder _types = new InstructionEncoder(new BlobBuilder()); private readonly InstructionEncoder _fieldRvas = new InstructionEncoder(new BlobBuilder()); private readonly InstructionEncoder _frozenObjects = new InstructionEncoder(new BlobBuilder()); private readonly InstructionEncoder _manifestResources = new InstructionEncoder(new BlobBuilder()); private readonly BlobBuilder _mangledNames = new BlobBuilder(); private List<(MethodDesc Method, string MangledName, int Size, int GcInfoSize)> _methods = new(); private Dictionary<MethodDesc, int> _methodEhInfo = new(); private Dictionary<string, int> _blobs = new(); private Dictionary<MethodDesc, List<(MethodDesc Method, int MangledName)>> _deduplicatedBodies = new(); public MstatObjectDumper(string fileName, TypeSystemContext context) { _fileName = fileName; var asmName = new AssemblyNameInfo(Path.GetFileName(fileName), version: new Version(VersionMajor, VersionMinor)); _emitter = new MstatEmitter(asmName, context); _emitter.AllowUseOfAddGlobalMethod(); } internal override void Begin() { } protected override void DumpObjectNode(NodeFactory factory, ObjectNode node, ObjectData objectData) { switch (node) { case EETypeNode eeType: _types.OpCode(ILOpCode.Ldtoken); _types.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(eeType.Type)); _types.LoadConstantI4(objectData.Data.Length); _types.LoadConstantI4(AppendMangledName(DependencyNodeCore<NodeFactory>.GetNodeName(node, factory))); break; case IMethodBodyNode methodBody: var codeInfo = (INodeWithCodeInfo)node; _methods.Add(( methodBody.Method, DependencyNodeCore<NodeFactory>.GetNodeName(node, factory), objectData.Data.Length, codeInfo.GCInfo.Length)); break; case MethodExceptionHandlingInfoNode ehInfoNode: _methodEhInfo.Add(ehInfoNode.Method, objectData.Data.Length); break; case FieldRvaDataNode rvaDataNode: _fieldRvas.OpCode(ILOpCode.Ldtoken); _fieldRvas.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(rvaDataNode.Field)); _fieldRvas.LoadConstantI4(rvaDataNode.Field.GetFieldRvaData().Length); _fieldRvas.LoadConstantI4(AppendMangledName(DependencyNodeCore<NodeFactory>.GetNodeName(node, factory))); // Breakdown of RVA data was introduced in MSTAT 2.1. Readers of 2.0 should still see it in the // global blobs section. We can remove it from there in 3.0. if (VersionMajor == 2) goto reportAsBlob; case ArrayOfFrozenObjectsNode: DumpFrozenRegion(factory); // Breakdown of frozen regions was introduced in MSTAT 2.1. Readers of 2.0 should still see it in the // global blobs section. We can remove it from there in 3.0. if (VersionMajor == 2) goto reportAsBlob; case ResourceDataNode resourceData: DumpResourceData(factory, resourceData); // Breakdown of resource data was introduced in MSTAT 2.1. Readers of 2.0 should still see it in the // global blobs section. We can remove it from there in 3.0. if (VersionMajor == 2) goto reportAsBlob; default: reportAsBlob: string nodeName = GetObjectNodeName(node); if (!_blobs.TryGetValue(nodeName, out int size)) size = 0; _blobs[nodeName] = size + objectData.Data.Length; break; } } public override void ReportFoldedNode(NodeFactory factory, ObjectNode originalNode, ISymbolNode targetNode) { if (originalNode is IMethodBodyNode originalBody && targetNode is IMethodBodyNode targetBody) { if (!_deduplicatedBodies.TryGetValue(originalBody.Method, out List<(MethodDesc, int)> targetBodies)) _deduplicatedBodies.Add(originalBody.Method, targetBodies = new List<(MethodDesc, int)>()); targetBodies.Add((targetBody.Method, AppendMangledName(targetBody.GetName(factory)))); } } private void DumpFrozenRegion(NodeFactory factory) { Debug.Assert(_frozenObjects.Offset == 0); foreach (FrozenObjectNode frozenObject in factory.MetadataManager.GetFrozenObjects()) { _frozenObjects.OpCode(ILOpCode.Ldtoken); _frozenObjects.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(frozenObject.ObjectType)); _frozenObjects.LoadConstantI4(frozenObject.Size); _frozenObjects.LoadConstantI4(AppendMangledName(DependencyNodeCore<NodeFactory>.GetNodeName(frozenObject, factory))); if (frozenObject is SerializedFrozenObjectNode serObj) { _frozenObjects.OpCode(ILOpCode.Ldtoken); _frozenObjects.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(serObj.OwningType)); } else { _frozenObjects.LoadConstantI4(0); } } } private void DumpResourceData(NodeFactory factory, ResourceDataNode resourceData) { Debug.Assert(_manifestResources.Offset == 0); foreach (ResourceIndexData resource in resourceData.GetOrCreateIndexData(factory)) { _manifestResources.LoadConstantI4(MetadataTokens.GetToken(_emitter.GetAssemblyRef(resource.Assembly))); _manifestResources.LoadString(_emitter.GetUserStringHandle(resource.ResourceName)); _manifestResources.LoadConstantI4(resource.Length); } } private int AppendMangledName(string mangledName) { int index = _mangledNames.Count; _mangledNames.WriteSerializedString(mangledName); return index; } internal override void End() { var methods = new InstructionEncoder(new BlobBuilder()); foreach (var m in _methods) { methods.OpCode(ILOpCode.Ldtoken); methods.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(m.Method)); methods.LoadConstantI4(m.Size); methods.LoadConstantI4(m.GcInfoSize); methods.LoadConstantI4(_methodEhInfo.GetValueOrDefault(m.Method)); methods.LoadConstantI4(AppendMangledName(m.MangledName)); } var blobs = new InstructionEncoder(new BlobBuilder()); foreach (var b in _blobs) { blobs.LoadString(_emitter.GetUserStringHandle(b.Key)); blobs.LoadConstantI4(b.Value); } var deduplicatedMethods = new InstructionEncoder(new BlobBuilder()); foreach (var d in _deduplicatedBodies) { deduplicatedMethods.OpCode(ILOpCode.Ldtoken); deduplicatedMethods.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(d.Key)); deduplicatedMethods.LoadConstantI4(d.Value.Count); foreach (var o in d.Value) { deduplicatedMethods.OpCode(ILOpCode.Ldtoken); deduplicatedMethods.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(o.Method)); deduplicatedMethods.LoadConstantI4(o.MangledName); } } _emitter.AddGlobalMethod("Methods", methods, 0); _emitter.AddGlobalMethod("Types", _types, 0); _emitter.AddGlobalMethod("Blobs", blobs, 0); _emitter.AddGlobalMethod("RvaFields", _fieldRvas, 0); _emitter.AddGlobalMethod("FrozenObjects", _frozenObjects, 0); _emitter.AddGlobalMethod("ManifestResources", _manifestResources, 0); _emitter.AddGlobalMethod("DeduplicatedMethods", deduplicatedMethods, 0); _emitter.AddPESection(".names", _mangledNames); using (var fs = File.Create(_fileName)) _emitter.SerializeToStream(fs); } private sealed class MstatEmitter : TypeSystemMetadataEmitter { private readonly List<(string Name, BlobBuilder Content)> _customSections = new(); public MstatEmitter(AssemblyNameInfo assemblyName, TypeSystemContext context, AssemblyFlags flags = default(AssemblyFlags), byte[] publicKeyArray = null) : base(assemblyName, context, flags, publicKeyArray) { } public void AddPESection(string name, BlobBuilder content) { _customSections.Add((name, content)); } protected override ManagedPEBuilder CreateManagedPEBuilder(BlobBuilder ilBuilder) { return new MstatPEBuilder(this, ilBuilder); } private sealed class MstatPEBuilder : ManagedPEBuilder { private readonly MstatEmitter _emitter; public MstatPEBuilder( MstatEmitter emitter, BlobBuilder ilStream) : base(PEHeaderBuilder.CreateLibraryHeader(), new MetadataRootBuilder(emitter.Builder), ilStream, deterministicIdProvider: content => s_contentId) { _emitter = emitter; } protected override ImmutableArray<Section> CreateSections() { ImmutableArray<Section> result = base.CreateSections(); return result.AddRange(_emitter._customSections.Select(s => new Section(s.Name, SectionCharacteristics.MemRead))); } protected override BlobBuilder SerializeSection(string name, SectionLocation location) { foreach (var section in _emitter._customSections) { if (section.Name == name) return section.Content; } return base.SerializeSection(name, location); } } } } }