Skip to content

Commit 59c1734

Browse files
Add more data into MSTAT files (#93842)
* Manifest resources are a large contributor to WinForms size, we better surface that. * Frozen objects can get also pretty large * And so does field RVA data (we have several 10+ kB large RVA static fields just in CoreLib).
1 parent 1d43977 commit 59c1734

File tree

5 files changed

+77
-11
lines changed

5 files changed

+77
-11
lines changed

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FieldRvaDataNode.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public class FieldRvaDataNode : ObjectNode, ISymbolDefinitionNode
1515
{
1616
private readonly EcmaField _field;
1717

18+
public EcmaField Field => _field;
19+
1820
public FieldRvaDataNode(EcmaField field)
1921
{
2022
Debug.Assert(field.HasRva);

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ResourceDataNode.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,9 @@ public IReadOnlyList<ResourceIndexData> GetOrCreateIndexData(NodeFactory factory
9696
if (factory.MetadataManager.IsManifestResourceBlocked(factory, module, resourceName))
9797
continue;
9898

99-
string assemblyName = module.GetName().FullName;
10099
BlobReader reader = resourceDirectory.GetReader((int)resource.Offset, resourceDirectory.Length - (int)resource.Offset);
101100
int length = (int)reader.ReadUInt32();
102-
ResourceIndexData indexData = new ResourceIndexData(assemblyName, resourceName, _totalLength, (int)resource.Offset + sizeof(int), module, length);
101+
ResourceIndexData indexData = new ResourceIndexData(module, resourceName, _totalLength, (int)resource.Offset + sizeof(int), module, length);
103102
_indexData.Add(indexData);
104103
_totalLength += length;
105104
}
@@ -149,9 +148,9 @@ private byte[] GenerateResourceBlob(NodeFactory factory)
149148
/// </summary>
150149
internal sealed class ResourceIndexData
151150
{
152-
public ResourceIndexData(string assemblyName, string resourceName, int nativeOffset, int ecmaOffset, EcmaModule ecmaModule, int length)
151+
public ResourceIndexData(EcmaAssembly assembly, string resourceName, int nativeOffset, int ecmaOffset, EcmaModule ecmaModule, int length)
153152
{
154-
AssemblyName = assemblyName;
153+
Assembly = assembly;
155154
ResourceName = resourceName;
156155
NativeOffset = nativeOffset;
157156
EcmaOffset = ecmaOffset;
@@ -160,9 +159,9 @@ public ResourceIndexData(string assemblyName, string resourceName, int nativeOff
160159
}
161160

162161
/// <summary>
163-
/// Full name of the assembly that contains the resource
162+
/// Assembly that contains the resource
164163
/// </summary>
165-
public string AssemblyName { get; }
164+
public EcmaAssembly Assembly { get; }
166165

167166
/// <summary>
168167
/// Name of the resource

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ResourceIndexNode.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ private byte[] GenerateIndexBlob(NodeFactory factory)
7474

7575
foreach (ResourceIndexData indexData in _resourceDataNode.GetOrCreateIndexData(factory))
7676
{
77-
Vertex asmName = nativeWriter.GetStringConstant(indexData.AssemblyName);
77+
string assemblyName = indexData.Assembly.GetName().FullName;
78+
Vertex asmName = nativeWriter.GetStringConstant(assemblyName);
7879
Vertex resourceName = nativeWriter.GetStringConstant(indexData.ResourceName);
7980
Vertex offsetVertex = nativeWriter.GetUnsignedConstant((uint)indexData.NativeOffset);
8081
Vertex lengthVertex = nativeWriter.GetUnsignedConstant((uint)indexData.Length);
@@ -83,7 +84,7 @@ private byte[] GenerateIndexBlob(NodeFactory factory)
8384
indexVertex = nativeWriter.GetTuple(indexVertex, offsetVertex);
8485
indexVertex = nativeWriter.GetTuple(indexVertex, lengthVertex);
8586

86-
int hashCode = TypeHashingAlgorithms.ComputeNameHashCode(indexData.AssemblyName);
87+
int hashCode = TypeHashingAlgorithms.ComputeNameHashCode(assemblyName);
8788
indexHashtable.Append((uint)hashCode, indexHashtableSection.Place(indexVertex));
8889
}
8990

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MstatObjectDumper.cs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
using System.Reflection.PortableExecutable;
1313

1414
using Internal.TypeSystem;
15+
using Internal.TypeSystem.Ecma;
1516

1617
using ILCompiler.DependencyAnalysis;
1718
using ILCompiler.DependencyAnalysisFramework;
1819

20+
using Debug = System.Diagnostics.Debug;
1921
using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData;
2022
using AssemblyName = System.Reflection.AssemblyName;
2123

@@ -24,12 +26,15 @@ namespace ILCompiler
2426
public class MstatObjectDumper : ObjectDumper
2527
{
2628
private const int VersionMajor = 2;
27-
private const int VersionMinor = 0;
29+
private const int VersionMinor = 1;
2830

2931
private readonly string _fileName;
3032
private readonly MstatEmitter _emitter;
3133

3234
private readonly InstructionEncoder _types = new InstructionEncoder(new BlobBuilder());
35+
private readonly InstructionEncoder _fieldRvas = new InstructionEncoder(new BlobBuilder());
36+
private readonly InstructionEncoder _frozenObjects = new InstructionEncoder(new BlobBuilder());
37+
private readonly InstructionEncoder _manifestResources = new InstructionEncoder(new BlobBuilder());
3338

3439
private readonly BlobBuilder _mangledNames = new BlobBuilder();
3540

@@ -71,7 +76,29 @@ protected override void DumpObjectNode(NodeFactory factory, ObjectNode node, Obj
7176
case MethodExceptionHandlingInfoNode ehInfoNode:
7277
_methodEhInfo.Add(ehInfoNode.Method, objectData.Data.Length);
7378
break;
79+
case FieldRvaDataNode rvaDataNode:
80+
_fieldRvas.OpCode(ILOpCode.Ldtoken);
81+
_fieldRvas.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(rvaDataNode.Field));
82+
_fieldRvas.LoadConstantI4(rvaDataNode.Field.GetFieldRvaData().Length);
83+
_fieldRvas.LoadConstantI4(AppendMangledName(DependencyNodeCore<NodeFactory>.GetNodeName(node, factory)));
84+
// Breakdown of RVA data was introduced in MSTAT 2.1. Readers of 2.0 should still see it in the
85+
// global blobs section. We can remove it from there in 3.0.
86+
if (VersionMajor == 2)
87+
goto reportAsBlob;
88+
case ArrayOfFrozenObjectsNode:
89+
DumpFrozenRegion(factory);
90+
// Breakdown of frozen regions was introduced in MSTAT 2.1. Readers of 2.0 should still see it in the
91+
// global blobs section. We can remove it from there in 3.0.
92+
if (VersionMajor == 2)
93+
goto reportAsBlob;
94+
case ResourceDataNode resourceData:
95+
DumpResourceData(factory, resourceData);
96+
// Breakdown of resource data was introduced in MSTAT 2.1. Readers of 2.0 should still see it in the
97+
// global blobs section. We can remove it from there in 3.0.
98+
if (VersionMajor == 2)
99+
goto reportAsBlob;
74100
default:
101+
reportAsBlob:
75102
string nodeName = GetObjectNodeName(node);
76103
if (!_blobs.TryGetValue(nodeName, out int size))
77104
size = 0;
@@ -80,6 +107,41 @@ protected override void DumpObjectNode(NodeFactory factory, ObjectNode node, Obj
80107
}
81108
}
82109

110+
private void DumpFrozenRegion(NodeFactory factory)
111+
{
112+
Debug.Assert(_frozenObjects.Offset == 0);
113+
114+
foreach (FrozenObjectNode frozenObject in factory.MetadataManager.GetFrozenObjects())
115+
{
116+
_frozenObjects.OpCode(ILOpCode.Ldtoken);
117+
_frozenObjects.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(frozenObject.ObjectType));
118+
_frozenObjects.LoadConstantI4(frozenObject.Size);
119+
_frozenObjects.LoadConstantI4(AppendMangledName(DependencyNodeCore<NodeFactory>.GetNodeName(frozenObject, factory)));
120+
121+
if (frozenObject is SerializedFrozenObjectNode serObj)
122+
{
123+
_frozenObjects.OpCode(ILOpCode.Ldtoken);
124+
_frozenObjects.Token(_emitter.EmitMetadataHandleForTypeSystemEntity(serObj.OwningType));
125+
}
126+
else
127+
{
128+
_frozenObjects.LoadConstantI4(0);
129+
}
130+
}
131+
}
132+
133+
private void DumpResourceData(NodeFactory factory, ResourceDataNode resourceData)
134+
{
135+
Debug.Assert(_manifestResources.Offset == 0);
136+
137+
foreach (ResourceIndexData resource in resourceData.GetOrCreateIndexData(factory))
138+
{
139+
_manifestResources.LoadConstantI4(MetadataTokens.GetToken(_emitter.GetAssemblyRef(resource.Assembly)));
140+
_manifestResources.LoadString(_emitter.GetUserStringHandle(resource.ResourceName));
141+
_manifestResources.LoadConstantI4(resource.Length);
142+
}
143+
}
144+
83145
private int AppendMangledName(string mangledName)
84146
{
85147
int index = _mangledNames.Count;
@@ -110,6 +172,9 @@ internal override void End()
110172
_emitter.AddGlobalMethod("Methods", methods, 0);
111173
_emitter.AddGlobalMethod("Types", _types, 0);
112174
_emitter.AddGlobalMethod("Blobs", blobs, 0);
175+
_emitter.AddGlobalMethod("RvaFields", _fieldRvas, 0);
176+
_emitter.AddGlobalMethod("FrozenObjects", _frozenObjects, 0);
177+
_emitter.AddGlobalMethod("ManifestResources", _manifestResources, 0);
113178

114179
_emitter.AddPESection(".names", _mangledNames);
115180

src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,8 +1071,7 @@ private void ImportStoreField(int token, bool isStatic)
10711071

10721072
private void ImportLoadString(int token)
10731073
{
1074-
// If we care, this can include allocating the frozen string node.
1075-
_dependencies.Add(_factory.SerializedStringObject(""), "ldstr");
1074+
_dependencies.Add(_factory.SerializedStringObject((string)_methodIL.GetObject(token)), "ldstr");
10761075
}
10771076

10781077
private void ImportBox(int token)

0 commit comments

Comments
 (0)