Represent field RVA data with a dedicated node (#72826)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Tue, 26 Jul 2022 06:20:16 +0000 (15:20 +0900)
committerGitHub <noreply@github.com>
Tue, 26 Jul 2022 06:20:16 +0000 (15:20 +0900)
We were using the general purpose `ReadOnlyDataBlobNode` but that meant that whenever we needed to refer to one, we had to read the RVA data into a freshly allocated array and then see if there's a node with that data.

Removes 200 MB of allocations while compiling the Techempower benchmark.

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FieldRvaDataNode.cs [new file with mode: 0644]
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj

index bd21f15..d4492d2 100644 (file)
@@ -142,10 +142,7 @@ namespace ILCompiler
             else
             {
                 // Use the typical field definition in case this is an instantiated generic type
-                field = field.GetTypicalFieldDefinition();
-                int fieldTypePack = (field.FieldType as MetadataType)?.GetClassLayout().PackingSize ?? 1;
-                return NodeFactory.ReadOnlyDataBlob(NameMangler.GetMangledFieldName(field),
-                    ((EcmaField)field).GetFieldRvaData(), Math.Max(NodeFactory.Target.PointerSize, fieldTypePack));
+                return NodeFactory.FieldRvaData((EcmaField)field.GetTypicalFieldDefinition());
             }
         }
 
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FieldRvaDataNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FieldRvaDataNode.cs
new file mode 100644 (file)
index 0000000..d1f9e3e
--- /dev/null
@@ -0,0 +1,56 @@
+// 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 Internal.Text;
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace ILCompiler.DependencyAnalysis
+{
+    public class FieldRvaDataNode : ObjectNode, ISymbolDefinitionNode
+    {
+        private readonly EcmaField _field;
+        
+        public FieldRvaDataNode(EcmaField field)
+        {
+            Debug.Assert(field.HasRva);
+            _field = field;
+        }
+
+        public override ObjectNodeSection Section => ObjectNodeSection.ReadOnlyDataSection;
+        public override bool StaticDependenciesAreComputed => true;
+
+        public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
+        {
+            sb.Append(nameMangler.GetMangledFieldName(_field));
+        }
+        public int Offset => 0;
+        public override bool IsShareable => true;
+
+        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
+        {
+            int fieldTypePack = (_field.FieldType as MetadataType)?.GetClassLayout().PackingSize ?? 1;
+            byte[] data = relocsOnly ? Array.Empty<byte>() : _field.GetFieldRvaData();
+            return new ObjectData(
+                data,
+                Array.Empty<Relocation>(),
+                Math.Max(factory.Target.PointerSize, fieldTypePack),
+                new ISymbolDefinitionNode[] { this });
+        }
+
+        protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);
+
+#if !SUPPORT_JIT
+        public override int ClassCode => -456126;
+
+        public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
+        {
+            return comparer.Compare(_field, ((FieldRvaDataNode)other)._field);
+        }
+#endif
+    }
+}
index 54efc8c..2e50681 100644 (file)
@@ -236,6 +236,11 @@ namespace ILCompiler.DependencyAnalysis
                 return new BlobNode(key.Name, ObjectNodeSection.ReadOnlyDataSection, key.Data, key.Alignment);
             });
 
+            _fieldRvaDataBlobs = new NodeCache<Internal.TypeSystem.Ecma.EcmaField, FieldRvaDataNode>(key =>
+            {
+                return new FieldRvaDataNode(key);
+            });
+
             _uninitializedWritableDataBlobs = new NodeCache<UninitializedWritableDataBlobKey, BlobNode>(key =>
             {
                 return new BlobNode(key.Name, ObjectNodeSection.BssSection, new byte[key.Size], key.Alignment);
@@ -708,6 +713,14 @@ namespace ILCompiler.DependencyAnalysis
         {
             return _readOnlyDataBlobs.GetOrAdd(new ReadOnlyDataBlobKey(name, blobData, alignment));
         }
+
+        private NodeCache<Internal.TypeSystem.Ecma.EcmaField, FieldRvaDataNode> _fieldRvaDataBlobs;
+
+        public ISymbolNode FieldRvaData(Internal.TypeSystem.Ecma.EcmaField field)
+        {
+            return _fieldRvaDataBlobs.GetOrAdd(field);
+        }
+
         private NodeCache<TypeDesc, SealedVTableNode> _sealedVtableNodes;
 
         internal SealedVTableNode SealedVTable(TypeDesc type)
index ad9b7e0..230de4f 100644 (file)
     <Compile Include="Compiler\DependencyAnalysis\DynamicDependencyAttributeAlgorithm.cs" />
     <Compile Include="Compiler\DependencyAnalysis\DynamicInvokeTemplateNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\ExternSymbolsImportedNodeProvider.cs" />
+    <Compile Include="Compiler\DependencyAnalysis\FieldRvaDataNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\IndirectionExtensions.cs" />
     <Compile Include="Compiler\DependencyAnalysis\InterfaceDispatchCellSectionNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\MethodExceptionHandlingInfoNode.cs" />