Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generation of structured object file dumps #73913

Merged
merged 1 commit into from
Aug 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<IlcArg Condition="$(NativeDebugSymbols) == 'true'" Include="-g" />
<IlcArg Condition="$(IlcDwarfVersion) == '5'" Include="--gdwarf-5" />
<IlcArg Condition="$(IlcGenerateMapFile) == 'true'" Include="--map:$(NativeIntermediateOutputPath)%(ManagedBinary.Filename).map.xml" />
<IlcArg Condition="$(IlcGenerateMstatFile) == 'true'" Include="--mstat:$(NativeIntermediateOutputPath)%(ManagedBinary.Filename).mstat" />
<IlcArg Condition="$(IlcGenerateDgmlFile) == 'true'" Include="--dgmllog:$(NativeIntermediateOutputPath)%(ManagedBinary.Filename).codegen.dgml.xml" />
<IlcArg Condition="$(IlcGenerateDgmlFile) == 'true'" Include="--scandgmllog:$(NativeIntermediateOutputPath)%(ManagedBinary.Filename).scan.dgml.xml" />
<IlcArg Include="@(RdXmlFile->'--rdxml:%(FullPath)')" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class MethodExceptionHandlingInfoNode : ObjectNode, ISymbolDefinitionNode
private readonly MethodDesc _owningMethod;
private readonly ObjectData _data;

public MethodDesc Method => _owningMethod;

public MethodExceptionHandlingInfoNode(MethodDesc owningMethod, ObjectData data)
{
_owningMethod = owningMethod;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// 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.IO;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;

using Internal.Text;
using Internal.TypeSystem;

using ILCompiler.DependencyAnalysis;

using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData;
using AssemblyName = System.Reflection.AssemblyName;
using System.Collections.Generic;
using static ILCompiler.DependencyAnalysis.ObjectNode;

namespace ILCompiler
{
public class MstatObjectDumper : ObjectDumper
{
private const int VersionMajor = 1;
private const int VersionMinor = 0;

private readonly string _fileName;
private readonly TypeSystemMetadataEmitter _emitter;

private readonly InstructionEncoder _types = new InstructionEncoder(new BlobBuilder());

private Dictionary<MethodDesc, (string MangledName, int Size, int GcInfoSize)> _methods = new();
private Dictionary<MethodDesc, int> _methodEhInfo = new();
private Dictionary<string, int> _blobs = new();

private Utf8StringBuilder _utf8StringBuilder = new Utf8StringBuilder();

public MstatObjectDumper(string fileName, TypeSystemContext context)
{
_fileName = fileName;
var asmName = new AssemblyName(Path.GetFileName(fileName));
asmName.Version = new Version(VersionMajor, VersionMinor);
_emitter = new TypeSystemMetadataEmitter(asmName, context);
_emitter.AllowUseOfAddGlobalMethod();
}

internal override void Begin()
{
}

protected override void DumpObjectNode(NameMangler mangler, ObjectNode node, ObjectData objectData)
{
string mangledName = null;
if (node is ISymbolNode symbol)
{
_utf8StringBuilder.Clear();
symbol.AppendMangledName(mangler, _utf8StringBuilder);
mangledName = _utf8StringBuilder.ToString();
}

switch (node)
{
case EETypeNode eeType:
SerializeSimpleEntry(_types, eeType.Type, mangledName, objectData);
break;
case IMethodBodyNode methodBody:
var codeInfo = (INodeWithCodeInfo)node;
_methods.Add(methodBody.Method, (mangledName, objectData.Data.Length, codeInfo.GCInfo.Length));
break;
case MethodExceptionHandlingInfoNode ehInfoNode:
_methodEhInfo.Add(ehInfoNode.Method, objectData.Data.Length);
break;
default:
string nodeName = GetObjectNodeName(node);
if (!_blobs.TryGetValue(nodeName, out int size))
size = 0;
_blobs[nodeName] = size + objectData.Data.Length;
break;
}
}

private void SerializeSimpleEntry(InstructionEncoder encoder, TypeSystemEntity entity, string mangledName, ObjectData blob)
{
encoder.OpCode(ILOpCode.Ldtoken);
encoder.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(entity));
encoder.LoadString(_emitter.GetUserStringHandle(mangledName));
encoder.LoadConstantI4(blob.Data.Length);
}

internal override void End()
{
var methods = new InstructionEncoder(new BlobBuilder());
foreach (var m in _methods)
{
methods.OpCode(ILOpCode.Ldtoken);
methods.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(m.Key));
methods.LoadString(_emitter.GetUserStringHandle(m.Value.MangledName));
methods.LoadConstantI4(m.Value.Size);
methods.LoadConstantI4(m.Value.GcInfoSize);
methods.LoadConstantI4(_methodEhInfo.GetValueOrDefault(m.Key));
}

var blobs = new InstructionEncoder(new BlobBuilder());
foreach (var b in _blobs)
{
blobs.LoadString(_emitter.GetUserStringHandle(b.Key));
blobs.LoadConstantI4(b.Value);
}

_emitter.AddGlobalMethod("Methods", methods, 0);
_emitter.AddGlobalMethod("Types", _types, 0);
_emitter.AddGlobalMethod("Blobs", blobs, 0);

using (var fs = File.OpenWrite(_fileName))
_emitter.SerializeToStream(fs);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.IO;
using System.Security.Cryptography;
using System.Xml;
using System.Collections.Generic;

using Internal.Text;

Expand All @@ -14,31 +12,14 @@

namespace ILCompiler
{
public class ObjectDumper : IObjectDumper
public abstract class ObjectDumper : IObjectDumper
{
private readonly string _fileName;
private SHA256 _sha256;
private XmlWriter _writer;
internal abstract void Begin();
internal abstract void End();
void IObjectDumper.DumpObjectNode(NameMangler mangler, ObjectNode node, ObjectData objectData) => DumpObjectNode(mangler, node, objectData);
protected abstract void DumpObjectNode(NameMangler mangler, ObjectNode node, ObjectData objectData);

public ObjectDumper(string fileName)
{
_fileName = fileName;
}

internal void Begin()
{
var settings = new XmlWriterSettings
{
CloseOutput = true,
Indent = true,
};

_sha256 = SHA256.Create();
_writer = XmlWriter.Create(File.CreateText(_fileName), settings);
_writer.WriteStartElement("ObjectNodes");
}

private static string GetObjectNodeName(ObjectNode node)
protected static string GetObjectNodeName(ObjectNode node)
{
string name = node.GetType().Name;

Expand All @@ -54,46 +35,42 @@ private static string GetObjectNodeName(ObjectNode node)
return name;
}

void IObjectDumper.DumpObjectNode(NameMangler mangler, ObjectNode node, ObjectData objectData)
public static ObjectDumper Compose(IEnumerable<ObjectDumper> dumpers)
{
string name = null;

_writer.WriteStartElement(GetObjectNodeName(node));

var symbolNode = node as ISymbolNode;
if (symbolNode != null)
{
Utf8StringBuilder sb = new Utf8StringBuilder();
symbolNode.AppendMangledName(mangler, sb);
name = sb.ToString();
_writer.WriteAttributeString("Name", name);
}
var dumpersList = new ArrayBuilder<ObjectDumper>();

_writer.WriteAttributeString("Length", objectData.Data.Length.ToStringInvariant());
_writer.WriteAttributeString("Hash", HashData(objectData.Data));
_writer.WriteEndElement();
foreach (var dumper in dumpers)
dumpersList.Add(dumper);

var nodeWithCodeInfo = node as INodeWithCodeInfo;
if (nodeWithCodeInfo != null)
return dumpersList.Count switch
{
_writer.WriteStartElement("GCInfo");
_writer.WriteAttributeString("Name", name);
_writer.WriteAttributeString("Length", nodeWithCodeInfo.GCInfo.Length.ToStringInvariant());
_writer.WriteAttributeString("Hash", HashData(nodeWithCodeInfo.GCInfo));
_writer.WriteEndElement();
}
0 => null,
1 => dumpersList[0],
_ => new ComposedObjectDumper(dumpersList.ToArray()),
};
}

private string HashData(byte[] data)
private class ComposedObjectDumper : ObjectDumper
{
return BitConverter.ToString(_sha256.ComputeHash(data)).Replace("-", "").ToLower();
}
private readonly ObjectDumper[] _dumpers;

internal void End()
{
_writer.WriteEndElement();
_writer.Dispose();
_writer = null;
public ComposedObjectDumper(ObjectDumper[] dumpers) => _dumpers = dumpers;

protected override void DumpObjectNode(NameMangler mangler, ObjectNode node, ObjectData objectData)
{
foreach (var d in _dumpers)
d.DumpObjectNode(mangler, node, objectData);
}
internal override void Begin()
{
foreach (var d in _dumpers)
d.Begin();
}
internal override void End()
{
foreach (var d in _dumpers)
d.End();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// 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.IO;
using System.Security.Cryptography;
using System.Xml;

using Internal.Text;

using ILCompiler.DependencyAnalysis;

using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData;

namespace ILCompiler
{
public class XmlObjectDumper : ObjectDumper
{
private readonly string _fileName;
private SHA256 _sha256;
private XmlWriter _writer;

public XmlObjectDumper(string fileName)
{
_fileName = fileName;
}

internal override void Begin()
{
var settings = new XmlWriterSettings
{
CloseOutput = true,
Indent = true,
};

_sha256 = SHA256.Create();
_writer = XmlWriter.Create(File.CreateText(_fileName), settings);
_writer.WriteStartElement("ObjectNodes");
}

protected override void DumpObjectNode(NameMangler mangler, ObjectNode node, ObjectData objectData)
{
string name = null;

_writer.WriteStartElement(GetObjectNodeName(node));

var symbolNode = node as ISymbolNode;
if (symbolNode != null)
{
Utf8StringBuilder sb = new Utf8StringBuilder();
symbolNode.AppendMangledName(mangler, sb);
name = sb.ToString();
_writer.WriteAttributeString("Name", name);
}

_writer.WriteAttributeString("Length", objectData.Data.Length.ToStringInvariant());
_writer.WriteAttributeString("Hash", HashData(objectData.Data));
_writer.WriteEndElement();

var nodeWithCodeInfo = node as INodeWithCodeInfo;
if (nodeWithCodeInfo != null)
{
_writer.WriteStartElement("GCInfo");
_writer.WriteAttributeString("Name", name);
_writer.WriteAttributeString("Length", nodeWithCodeInfo.GCInfo.Length.ToStringInvariant());
_writer.WriteAttributeString("Hash", HashData(nodeWithCodeInfo.GCInfo));
_writer.WriteEndElement();
}
}

private string HashData(byte[] data)
{
return BitConverter.ToString(_sha256.ComputeHash(data)).Replace("-", "").ToLower();
}

internal override void End()
{
_writer.WriteEndElement();
_writer.Dispose();
_writer = null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@
<Compile Include="..\..\Common\TypeSystem\CodeGen\NativeStructType.CodeGen.cs">
<Link>TypeSystem\CodeGen\NativeStructType.CodeGen.cs</Link>
</Compile>
<Compile Include="..\..\Common\TypeSystem\MetadataEmitter\TypeSystemMetadataEmitter.cs">
<Link>TypeSystem\MetadataEmitter\TypeSystemMetadataEmitter.cs</Link>
</Compile>
<Compile Include="..\..\Common\Internal\Runtime\GCDescEncoder.cs">
<Link>Common\GCDescEncoder.cs</Link>
</Compile>
Expand Down Expand Up @@ -422,6 +425,7 @@
<Compile Include="Compiler\IInliningPolicy.cs" />
<Compile Include="Compiler\ManifestResourceBlockingPolicy.cs" />
<Compile Include="Compiler\MethodImportationErrorProvider.cs" />
<Compile Include="Compiler\MstatObjectDumper.cs" />
<Compile Include="Compiler\NoMetadataBlockingPolicy.cs" />
<Compile Include="Compiler\DependencyAnalysis\FrozenObjectNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\GCStaticsPreInitDataNode.cs" />
Expand Down Expand Up @@ -592,6 +596,7 @@
<Compile Include="Compiler\Logging\DocumentationSignatureParser.cs" />
<Compile Include="Compiler\Logging\MessageContainer.cs" />
<Compile Include="Compiler\Logging\MessageOrigin.cs" />
<Compile Include="Compiler\XmlObjectDumper.cs" />
<Compile Include="IL\ILImporter.Scanner.cs" />
<Compile Include="IL\Stubs\PInvokeILProvider.cs" />
<Compile Include="IL\Stubs\StartupCode\AppContextInitializerMethod.cs" />
Expand Down
Loading