Skip to content

Commit

Permalink
Improve Crossgen2 map file emitter (dotnet#35459)
Browse files Browse the repository at this point in the history
* Improve Crossgen2 map file emitter

I have rewritten the file name emitter with two main goals in mind:

1) Fix the long-standing problem that map file wasn't showing true
RVA's of the individual symbols / nodes, making it harder to
correlate its information with in-memory R2R PE layout.

2) Add section size and statistics section roughly mimicking what
JanV presented in his recent analytic breakdown of R2R contents.

Thanks

Tomas
  • Loading branch information
trylek authored Apr 27, 2020
1 parent f283945 commit a070557
Show file tree
Hide file tree
Showing 6 changed files with 329 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ internal class ReadyToRunObjectWriter
private readonly IEnumerable<DependencyNode> _nodes;

/// <summary>
/// True when the executable generator should output a map file.
/// Set to non-null when the executable generator should output a map file.
/// </summary>
private readonly bool _generateMapFile;
private readonly MapFileBuilder _mapFileBuilder;

#if DEBUG
private struct NodeInfo
Expand All @@ -78,31 +78,22 @@ public ReadyToRunObjectWriter(string objectFilePath, EcmaModule componentModule,
_componentModule = componentModule;
_nodes = nodes;
_nodeFactory = factory;
_generateMapFile = generateMapFile;

if (generateMapFile)
{
_mapFileBuilder = new MapFileBuilder();
}
}

public void EmitPortableExecutable()
{
bool succeeded = false;

FileStream mapFileStream = null;
TextWriter mapFile = null;

try
{
if (_generateMapFile)
{
string mapFileName = Path.ChangeExtension(_objectFilePath, ".map");
mapFileStream = new FileStream(mapFileName, FileMode.Create, FileAccess.Write);
mapFile = new StreamWriter(mapFileStream);
}

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();

if (mapFile != null)
mapFile.WriteLine($@"R2R object emission started: {DateTime.Now}");

PEHeaderBuilder headerBuilder;
int timeDateStamp;
ISymbolNode r2rHeaderExportSymbol;
Expand Down Expand Up @@ -167,7 +158,7 @@ public void EmitPortableExecutable()

string name = null;

if (mapFile != null)
if (_mapFileBuilder != null)
{
name = depNode.GetType().ToString();
int firstGeneric = name.IndexOf('[');
Expand All @@ -182,7 +173,7 @@ public void EmitPortableExecutable()
}
}

EmitObjectData(r2rPeBuilder, nodeContents, nodeIndex, name, node.Section, mapFile);
EmitObjectData(r2rPeBuilder, nodeContents, nodeIndex, name, node.Section, _mapFileBuilder);
}

if (!_nodeFactory.CompilationModuleGroup.IsCompositeBuildMode || _componentModule != null)
Expand All @@ -201,6 +192,11 @@ public void EmitPortableExecutable()
{
r2rPeBuilder.Write(peStream, timeDateStamp);

if (_mapFileBuilder != null)
{
_mapFileBuilder.SetFileSize(peStream.Length);
}

// Compute MD5 hash of the output image and store that in the native DebugDirectory entry
using (var md5Hash = MD5.Create())
{
Expand All @@ -214,25 +210,18 @@ public void EmitPortableExecutable()
}
}

if (mapFile != null)
if (_mapFileBuilder != null)
{
mapFile.WriteLine($@"R2R object emission finished: {DateTime.Now}, {stopwatch.ElapsedMilliseconds} msecs");
mapFile.Flush();
mapFileStream.Flush();
r2rPeBuilder.AddSections(_mapFileBuilder);

string mapFileName = Path.ChangeExtension(_objectFilePath, ".map");
_mapFileBuilder.Save(mapFileName);
}

succeeded = true;
}
finally
{
if (mapFile != null)
{
mapFile.Dispose();
}
if (mapFileStream != null)
{
mapFileStream.Dispose();
}
if (!succeeded)
{
// If there was an exception while generating the OBJ file, make sure we don't leave the unfinished
Expand Down Expand Up @@ -264,7 +253,7 @@ public void EmitPortableExecutable()
/// <param name="name">Textual representation of the ObjecData blob in the map file</param>
/// <param name="section">Section to emit the blob into</param>
/// <param name="mapFile">Map file output stream</param>
private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int nodeIndex, string name, ObjectNodeSection section, TextWriter mapFile)
private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int nodeIndex, string name, ObjectNodeSection section, MapFileBuilder mapFileBuilder)
{
#if DEBUG
for (int symbolIndex = 0; symbolIndex < data.DefinedSymbols.Length; symbolIndex++)
Expand All @@ -283,7 +272,7 @@ private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int node
}
#endif

r2rPeBuilder.AddObjectData(data, section, name, mapFile);
r2rPeBuilder.AddObjectData(data, section, name, mapFileBuilder);
}

public static void EmitObject(string objectFilePath, EcmaModule componentModule, IEnumerable<DependencyNode> nodes, NodeFactory factory, bool generateMapFile)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,5 +303,6 @@ public void InitializeInliningInfo(MethodDesc[] inlinedMethods)

public int Offset => 0;
public override bool IsShareable => throw new NotImplementedException();
public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => IsEmpty;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
<Compile Include="..\..\Common\JitInterface\CorInfoTypes.VarInfo.cs" Link="JitInterface\CorInfoTypes.VarInfo.cs" />
<Compile Include="..\..\Common\JitInterface\SystemVStructClassificator.cs" Link="JitInterface\SystemVStructClassificator.cs" />
<Compile Include="..\..\Common\TypeSystem\Interop\InteropTypes.cs" Link="Interop\InteropTypes.cs" />
<Compile Include="ObjectWriter\MapFileBuilder.cs" />
<Compile Include="CodeGen\ReadyToRunObjectWriter.cs" />
<Compile Include="Compiler\CompilationModuleGroup.ReadyToRun.cs" />
<Compile Include="Compiler\DependencyAnalysis\AllMethodsOnTypeNode.cs" />
Expand Down
Loading

0 comments on commit a070557

Please sign in to comment.