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 using Debug = System.Diagnostics.Debug;
12 
13 namespace ILCompiler.DependencyAnalysis
14 {
15     class ClassConstructorContextMap : ObjectNode, ISymbolDefinitionNode
16     {
17         private ObjectAndOffsetSymbolNode _endSymbol;
18         private ExternalReferencesTableNode _externalReferences;
19 
ClassConstructorContextMap(ExternalReferencesTableNode externalReferences)20         public ClassConstructorContextMap(ExternalReferencesTableNode externalReferences)
21         {
22             _endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__type_to_cctorContext_map_End", true);
23             _externalReferences = externalReferences;
24         }
25 
26         public ISymbolDefinitionNode EndSymbol => _endSymbol;
27 
AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)28         public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
29         {
30             sb.Append(nameMangler.CompilationUnitPrefix).Append("__type_to_cctorContext_map");
31         }
32         public int Offset => 0;
33 
34         public override ObjectNodeSection Section => _externalReferences.Section;
35         public override bool IsShareable => false;
36 
37         public override bool StaticDependenciesAreComputed => true;
38 
39         public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection;
40 
41         protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);
42 
GetData(NodeFactory factory, bool relocsOnly = false)43         public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
44         {
45             // This node does not trigger generation of other nodes.
46             if (relocsOnly)
47                 return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
48 
49             var writer = new NativeWriter();
50             var typeMapHashTable = new VertexHashtable();
51 
52             Section hashTableSection = writer.NewSection();
53             hashTableSection.Place(typeMapHashTable);
54 
55             foreach (var node in factory.MetadataManager.GetCctorContextMapping())
56             {
57                 MetadataType type = node.Type;
58 
59                 Debug.Assert(factory.TypeSystemContext.HasLazyStaticConstructor(type));
60 
61                 // If this type doesn't generate an EEType in the current compilation, don't report it in the table.
62                 // If nobody can get to the EEType, they can't ask to run the cctor. We don't need to force generate it.
63                 if (!factory.MetadataManager.TypeGeneratesEEType(type))
64                     continue;
65 
66                 // Hash table is hashed by the hashcode of the owning type.
67                 // Each entry has: the EEType of the type, followed by the non-GC static base.
68                 // The non-GC static base is prefixed by the class constructor context.
69                 Vertex vertex = writer.GetTuple(
70                     writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.NecessaryTypeSymbol(type))),
71                     writer.GetUnsignedConstant(_externalReferences.GetIndex(node))
72                     );
73 
74                 int hashCode = 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         protected internal override int ClassCode => (int)ObjectNodeOrder.ClassConstructorContextMap;
87     }
88 }
89