1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 
7 using Internal.NativeFormat;
8 using Internal.Text;
9 using Internal.TypeSystem;
10 
11 namespace ILCompiler.DependencyAnalysis
12 {
13     /// <summary>
14     /// Represents a map between EETypes and metadata records within the <see cref="MetadataNode"/>.
15     /// </summary>
16     internal sealed class TypeMetadataMapNode : ObjectNode, ISymbolDefinitionNode
17     {
18         private ObjectAndOffsetSymbolNode _endSymbol;
19         private ExternalReferencesTableNode _externalReferences;
20 
TypeMetadataMapNode(ExternalReferencesTableNode externalReferences)21         public TypeMetadataMapNode(ExternalReferencesTableNode externalReferences)
22         {
23             _endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__type_to_metadata_map_End", true);
24             _externalReferences = externalReferences;
25         }
26 
27         public ISymbolNode EndSymbol => _endSymbol;
28 
AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)29         public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
30         {
31             sb.Append(nameMangler.CompilationUnitPrefix).Append("__type_to_metadata_map");
32         }
33         public int Offset => 0;
34         public override bool IsShareable => false;
35 
36         public override ObjectNodeSection Section => _externalReferences.Section;
37 
38         public override bool StaticDependenciesAreComputed => true;
39 
40         public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection;
41 
42         protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);
43 
GetData(NodeFactory factory, bool relocsOnly = false)44         public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
45         {
46             // This node does not trigger generation of other nodes.
47             if (relocsOnly)
48                 return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
49 
50             var writer = new NativeWriter();
51             var typeMapHashTable = new VertexHashtable();
52 
53             Section hashTableSection = writer.NewSection();
54             hashTableSection.Place(typeMapHashTable);
55 
56             foreach (var mappingEntry in factory.MetadataManager.GetTypeDefinitionMapping(factory))
57             {
58                 if (!factory.CompilationModuleGroup.ContainsType(mappingEntry.Entity))
59                     continue;
60 
61                 // Types that don't have EETypes don't need mapping table entries because there's no risk of them
62                 // not unifying to the same System.Type at runtime.
63                 if (!factory.MetadataManager.TypeGeneratesEEType(mappingEntry.Entity))
64                     continue;
65 
66                 // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted.
67                 IEETypeNode typeSymbol = factory.NecessaryTypeSymbol(mappingEntry.Entity);
68 
69                 Vertex vertex = writer.GetTuple(
70                     writer.GetUnsignedConstant(_externalReferences.GetIndex(typeSymbol)),
71                     writer.GetUnsignedConstant((uint)mappingEntry.MetadataHandle)
72                     );
73 
74                 int hashCode = typeSymbol.Type.GetHashCode();
75                 typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
76             }
77 
78             byte[] hashTableBytes = writer.Save();
79 
80             _endSymbol.SetSymbolOffset(hashTableBytes.Length);
81 
82             return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol });
83         }
84 
85         protected internal override int Phase => (int)ObjectNodePhase.Ordered;
86 
87         protected internal override int ClassCode => (int)ObjectNodeOrder.TypeMetadataMapNode;
88     }
89 }
90