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 using System.Diagnostics; 7 8 using Internal.Text; 9 using Internal.TypeSystem; 10 using Internal.NativeFormat; 11 12 using FieldTableFlags = Internal.Runtime.FieldTableFlags; 13 14 namespace ILCompiler.DependencyAnalysis 15 { 16 /// <summary> 17 /// Represents a map between reflection metadata and native field offsets. 18 /// </summary> 19 internal sealed class ReflectionFieldMapNode : ObjectNode, ISymbolDefinitionNode 20 { 21 private ObjectAndOffsetSymbolNode _endSymbol; 22 private ExternalReferencesTableNode _externalReferences; 23 ReflectionFieldMapNode(ExternalReferencesTableNode externalReferences)24 public ReflectionFieldMapNode(ExternalReferencesTableNode externalReferences) 25 { 26 _endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__field_to_offset_map_End", true); 27 _externalReferences = externalReferences; 28 } 29 30 public ISymbolNode EndSymbol => _endSymbol; 31 AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)32 public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) 33 { 34 sb.Append(nameMangler.CompilationUnitPrefix).Append("__field_to_offset_map"); 35 } 36 37 public int Offset => 0; 38 public override bool IsShareable => false; 39 40 public override ObjectNodeSection Section => _externalReferences.Section; 41 42 public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; 43 44 public override bool StaticDependenciesAreComputed => true; 45 46 protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); 47 GetData(NodeFactory factory, bool relocsOnly = false)48 public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) 49 { 50 // This node does not trigger generation of other nodes. 51 if (relocsOnly) 52 return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this }); 53 54 var writer = new NativeWriter(); 55 var fieldMapHashTable = new VertexHashtable(); 56 57 Section hashTableSection = writer.NewSection(); 58 hashTableSection.Place(fieldMapHashTable); 59 60 foreach (var fieldMapping in factory.MetadataManager.GetFieldMapping(factory)) 61 { 62 FieldDesc field = fieldMapping.Entity; 63 64 if (field.IsLiteral || field.HasRva) 65 continue; 66 67 FieldTableFlags flags; 68 if (field.IsThreadStatic) 69 { 70 flags = FieldTableFlags.ThreadStatic | FieldTableFlags.FieldOffsetEncodedDirectly; 71 } 72 else if (field.IsStatic) 73 { 74 flags = FieldTableFlags.Static; 75 76 if (field.HasGCStaticBase) 77 flags |= FieldTableFlags.IsGcSection; 78 79 if (field.OwningType.HasInstantiation) 80 flags |= FieldTableFlags.FieldOffsetEncodedDirectly; 81 } 82 else 83 { 84 flags = FieldTableFlags.Instance | FieldTableFlags.FieldOffsetEncodedDirectly; 85 } 86 87 if (fieldMapping.MetadataHandle != 0) 88 flags |= FieldTableFlags.HasMetadataHandle; 89 90 if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) 91 flags |= FieldTableFlags.IsAnyCanonicalEntry; 92 93 if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Universal)) 94 flags |= FieldTableFlags.IsUniversalCanonicalEntry; 95 96 // Grammar of a hash table entry: 97 // Flags + DeclaringType + MdHandle or Name + Cookie or Ordinal or Offset 98 99 Vertex vertex = writer.GetUnsignedConstant((uint)flags); 100 101 uint declaringTypeId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(field.OwningType)); 102 vertex = writer.GetTuple(vertex, 103 writer.GetUnsignedConstant(declaringTypeId)); 104 105 if ((flags & FieldTableFlags.HasMetadataHandle) != 0) 106 { 107 // Only store the offset portion of the metadata handle to get better integer compression 108 vertex = writer.GetTuple(vertex, 109 writer.GetUnsignedConstant((uint)(fieldMapping.MetadataHandle & MetadataManager.MetadataOffsetMask))); 110 } 111 else 112 { 113 // No metadata handle means we need to store name 114 vertex = writer.GetTuple(vertex, 115 writer.GetStringConstant(field.Name)); 116 } 117 118 if ((flags & FieldTableFlags.IsUniversalCanonicalEntry) != 0) 119 { 120 vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(checked((uint)field.GetFieldOrdinal()))); 121 } 122 else 123 { 124 switch (flags & FieldTableFlags.StorageClass) 125 { 126 case FieldTableFlags.ThreadStatic: 127 if (factory.Target.Abi == TargetAbi.ProjectN) 128 { 129 if (!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) 130 { 131 ISymbolNode tlsOffsetForType = ((UtcNodeFactory)factory).TypeThreadStaticsOffsetSymbol((MetadataType)field.OwningType); 132 vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(tlsOffsetForType))); 133 } 134 vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(field.Offset.AsInt))); 135 } 136 else 137 { 138 // TODO: CoreRT 139 continue; 140 } 141 break; 142 143 case FieldTableFlags.Static: 144 { 145 if (field.OwningType.HasInstantiation) 146 { 147 vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(field.Offset.AsInt))); 148 } 149 else 150 { 151 MetadataType metadataType = (MetadataType)field.OwningType; 152 153 ISymbolNode staticsNode = field.HasGCStaticBase ? 154 factory.TypeGCStaticsSymbol(metadataType) : 155 factory.TypeNonGCStaticsSymbol(metadataType); 156 157 if (!field.HasGCStaticBase || factory.Target.Abi == TargetAbi.ProjectN) 158 { 159 uint index = _externalReferences.GetIndex(staticsNode, field.Offset.AsInt); 160 vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(index)); 161 } 162 else 163 { 164 Debug.Assert(field.HasGCStaticBase && factory.Target.Abi == TargetAbi.CoreRT); 165 166 uint index = _externalReferences.GetIndex(staticsNode); 167 vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(index)); 168 vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(field.Offset.AsInt))); 169 } 170 } 171 } 172 break; 173 174 case FieldTableFlags.Instance: 175 vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)field.Offset.AsInt)); 176 break; 177 } 178 } 179 180 int hashCode = field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific).GetHashCode(); 181 fieldMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); 182 } 183 184 byte[] hashTableBytes = writer.Save(); 185 186 _endSymbol.SetSymbolOffset(hashTableBytes.Length); 187 188 return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }); 189 } 190 191 protected internal override int Phase => (int)ObjectNodePhase.Ordered; 192 protected internal override int ClassCode => (int)ObjectNodeOrder.ReflectionFieldMapNode; 193 } 194 } 195