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