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.Collections.Generic; 6 7 using Internal.TypeSystem; 8 9 using ILCompiler.Metadata; 10 using ILCompiler.DependencyAnalysis; 11 12 using Debug = System.Diagnostics.Debug; 13 14 namespace ILCompiler 15 { 16 /// <summary> 17 /// A metadata manager that knows the full set of metadata ahead of time. 18 /// </summary> 19 public sealed class AnalysisBasedMetadataManager : GeneratingMetadataManager, ICompilationRootProvider 20 { 21 private readonly List<ModuleDesc> _modulesWithMetadata; 22 23 private readonly Dictionary<TypeDesc, MetadataCategory> _reflectableTypes = new Dictionary<TypeDesc, MetadataCategory>(); 24 private readonly Dictionary<MethodDesc, MetadataCategory> _reflectableMethods = new Dictionary<MethodDesc, MetadataCategory>(); 25 private readonly Dictionary<FieldDesc, MetadataCategory> _reflectableFields = new Dictionary<FieldDesc, MetadataCategory>(); 26 AnalysisBasedMetadataManager( ModuleDesc generatedAssembly, CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy, string logFile, StackTraceEmissionPolicy stackTracePolicy, IEnumerable<ModuleDesc> modulesWithMetadata, IEnumerable<ReflectableEntity<TypeDesc>> reflectableTypes, IEnumerable<ReflectableEntity<MethodDesc>> reflectableMethods, IEnumerable<ReflectableEntity<FieldDesc>> reflectableFields)27 public AnalysisBasedMetadataManager( 28 ModuleDesc generatedAssembly, 29 CompilerTypeSystemContext typeSystemContext, 30 MetadataBlockingPolicy blockingPolicy, 31 string logFile, 32 StackTraceEmissionPolicy stackTracePolicy, 33 IEnumerable<ModuleDesc> modulesWithMetadata, 34 IEnumerable<ReflectableEntity<TypeDesc>> reflectableTypes, 35 IEnumerable<ReflectableEntity<MethodDesc>> reflectableMethods, 36 IEnumerable<ReflectableEntity<FieldDesc>> reflectableFields) 37 : base(generatedAssembly, typeSystemContext, blockingPolicy, logFile, stackTracePolicy) 38 { 39 _modulesWithMetadata = new List<ModuleDesc>(modulesWithMetadata); 40 41 foreach (var refType in reflectableTypes) 42 { 43 _reflectableTypes.Add(refType.Entity, refType.Category); 44 } 45 46 foreach (var refMethod in reflectableMethods) 47 { 48 // Asking for description or runtime mapping for a member without asking 49 // for the owning type would mean we can't actually satisfy the request. 50 Debug.Assert((refMethod.Category & MetadataCategory.Description) == 0 51 || (_reflectableTypes[refMethod.Entity.OwningType] & MetadataCategory.Description) != 0); 52 Debug.Assert((refMethod.Category & MetadataCategory.RuntimeMapping) == 0 53 || (_reflectableTypes[refMethod.Entity.OwningType] & MetadataCategory.RuntimeMapping) != 0); 54 _reflectableMethods.Add(refMethod.Entity, refMethod.Category); 55 56 MethodDesc canonMethod = refMethod.Entity.GetCanonMethodTarget(CanonicalFormKind.Specific); 57 if (refMethod.Entity != canonMethod) 58 { 59 if (!_reflectableMethods.TryGetValue(canonMethod, out MetadataCategory category)) 60 category = 0; 61 _reflectableMethods[canonMethod] = category | refMethod.Category; 62 } 63 } 64 65 foreach (var refField in reflectableFields) 66 { 67 // Asking for description or runtime mapping for a member without asking 68 // for the owning type would mean we can't actually satisfy the request. 69 Debug.Assert((refField.Category & MetadataCategory.Description) == 0 70 || (_reflectableTypes[refField.Entity.OwningType] & MetadataCategory.Description) != 0); 71 Debug.Assert((refField.Category & MetadataCategory.RuntimeMapping) == 0 72 || (_reflectableTypes[refField.Entity.OwningType] & MetadataCategory.RuntimeMapping) != 0); 73 _reflectableFields.Add(refField.Entity, refField.Category); 74 } 75 76 #if DEBUG 77 HashSet<ModuleDesc> moduleHash = new HashSet<ModuleDesc>(_modulesWithMetadata); 78 foreach (var refType in reflectableTypes) 79 { 80 // The instantiated types need to agree on the Description bit with the definition. 81 // GetMetadataCategory relies on that. 82 Debug.Assert((GetMetadataCategory(refType.Entity.GetTypeDefinition()) & MetadataCategory.Description) 83 == (GetMetadataCategory(refType.Entity) & MetadataCategory.Description)); 84 85 Debug.Assert(!(refType.Entity is MetadataType) || moduleHash.Contains(((MetadataType)refType.Entity).Module)); 86 } 87 88 foreach (var refMethod in reflectableMethods) 89 { 90 // The instantiated methods need to agree on the Description bit with the definition. 91 // GetMetadataCategory relies on that. 92 Debug.Assert((GetMetadataCategory(refMethod.Entity.GetTypicalMethodDefinition()) & MetadataCategory.Description) 93 == (GetMetadataCategory(refMethod.Entity) & MetadataCategory.Description)); 94 } 95 96 foreach (var refField in reflectableFields) 97 { 98 // The instantiated fields need to agree on the Description bit with the definition. 99 // GetMetadataCategory relies on that. 100 Debug.Assert((GetMetadataCategory(refField.Entity.GetTypicalFieldDefinition()) & MetadataCategory.Description) 101 == (GetMetadataCategory(refField.Entity) & MetadataCategory.Description)); 102 } 103 #endif 104 } 105 GetCompilationModulesWithMetadata()106 public override IEnumerable<ModuleDesc> GetCompilationModulesWithMetadata() 107 { 108 return _modulesWithMetadata; 109 } 110 ComputeMetadata(NodeFactory factory, out byte[] metadataBlob, out List<MetadataMapping<MetadataType>> typeMappings, out List<MetadataMapping<MethodDesc>> methodMappings, out List<MetadataMapping<FieldDesc>> fieldMappings, out List<MetadataMapping<MethodDesc>> stackTraceMapping)111 protected override void ComputeMetadata(NodeFactory factory, 112 out byte[] metadataBlob, 113 out List<MetadataMapping<MetadataType>> typeMappings, 114 out List<MetadataMapping<MethodDesc>> methodMappings, 115 out List<MetadataMapping<FieldDesc>> fieldMappings, 116 out List<MetadataMapping<MethodDesc>> stackTraceMapping) 117 { 118 ComputeMetadata(new Policy(_blockingPolicy, this), factory, 119 out metadataBlob, 120 out typeMappings, 121 out methodMappings, 122 out fieldMappings, 123 out stackTraceMapping); 124 } 125 GetMetadataCategory(MethodDesc method)126 protected sealed override MetadataCategory GetMetadataCategory(MethodDesc method) 127 { 128 if (_reflectableMethods.TryGetValue(method, out MetadataCategory value)) 129 return value; 130 return 0; 131 } 132 GetMetadataCategory(TypeDesc type)133 protected sealed override MetadataCategory GetMetadataCategory(TypeDesc type) 134 { 135 if (_reflectableTypes.TryGetValue(type, out MetadataCategory value)) 136 return value; 137 return 0; 138 } 139 GetMetadataCategory(FieldDesc field)140 protected sealed override MetadataCategory GetMetadataCategory(FieldDesc field) 141 { 142 if (_reflectableFields.TryGetValue(field, out MetadataCategory value)) 143 return value; 144 return 0; 145 } 146 GetFieldsWithRuntimeMapping()147 protected override IEnumerable<FieldDesc> GetFieldsWithRuntimeMapping() 148 { 149 foreach (var pair in _reflectableFields) 150 { 151 if ((pair.Value & MetadataCategory.RuntimeMapping) != 0) 152 yield return pair.Key; 153 } 154 } 155 ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider)156 void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider) 157 { 158 // We go over all the types and members that need a runtime artiface present in the 159 // compiled executable and root it. 160 161 const string reason = "Reflection"; 162 163 foreach (var pair in _reflectableTypes) 164 { 165 if ((pair.Value & MetadataCategory.RuntimeMapping) != 0) 166 rootProvider.AddCompilationRoot(pair.Key, reason); 167 } 168 169 foreach (var pair in _reflectableMethods) 170 { 171 if ((pair.Value & MetadataCategory.RuntimeMapping) != 0) 172 { 173 MethodDesc method = pair.Key; 174 175 // We need to root virtual methods as if they were called virtually. 176 // This will possibly trigger the generation of other overrides too. 177 if (method.IsVirtual) 178 rootProvider.RootVirtualMethodForReflection(method, reason); 179 180 if (!method.IsAbstract) 181 rootProvider.AddCompilationRoot(pair.Key, reason); 182 } 183 } 184 185 foreach (var pair in _reflectableFields) 186 { 187 if ((pair.Value & MetadataCategory.RuntimeMapping) != 0) 188 { 189 FieldDesc field = pair.Key; 190 191 // We only care about static fields at this point. Instance fields don't need 192 // runtime artifacts generated in the image. 193 if (field.IsStatic && !field.IsLiteral) 194 { 195 if (field.IsThreadStatic) 196 rootProvider.RootThreadStaticBaseForType(field.OwningType, reason); 197 else if (field.HasGCStaticBase) 198 rootProvider.RootGCStaticBaseForType(field.OwningType, reason); 199 else 200 rootProvider.RootNonGCStaticBaseForType(field.OwningType, reason); 201 } 202 } 203 } 204 } 205 206 private struct Policy : IMetadataPolicy 207 { 208 private readonly MetadataBlockingPolicy _blockingPolicy; 209 private readonly ExplicitScopeAssemblyPolicyMixin _explicitScopeMixin; 210 private readonly AnalysisBasedMetadataManager _parent; 211 PolicyILCompiler.AnalysisBasedMetadataManager.Policy212 public Policy(MetadataBlockingPolicy blockingPolicy, 213 AnalysisBasedMetadataManager parent) 214 { 215 _blockingPolicy = blockingPolicy; 216 _parent = parent; 217 _explicitScopeMixin = new ExplicitScopeAssemblyPolicyMixin(); 218 } 219 GeneratesMetadataILCompiler.AnalysisBasedMetadataManager.Policy220 public bool GeneratesMetadata(FieldDesc fieldDef) 221 { 222 return (_parent.GetMetadataCategory(fieldDef) & MetadataCategory.Description) != 0; 223 } 224 GeneratesMetadataILCompiler.AnalysisBasedMetadataManager.Policy225 public bool GeneratesMetadata(MethodDesc methodDef) 226 { 227 return (_parent.GetMetadataCategory(methodDef) & MetadataCategory.Description) != 0; 228 } 229 GeneratesMetadataILCompiler.AnalysisBasedMetadataManager.Policy230 public bool GeneratesMetadata(MetadataType typeDef) 231 { 232 return (_parent.GetMetadataCategory(typeDef) & MetadataCategory.Description) != 0; 233 } 234 IsBlockedILCompiler.AnalysisBasedMetadataManager.Policy235 public bool IsBlocked(MetadataType typeDef) 236 { 237 return _blockingPolicy.IsBlocked(typeDef); 238 } 239 IsBlockedILCompiler.AnalysisBasedMetadataManager.Policy240 public bool IsBlocked(MethodDesc methodDef) 241 { 242 return _blockingPolicy.IsBlocked(methodDef); 243 } 244 GetModuleOfTypeILCompiler.AnalysisBasedMetadataManager.Policy245 public ModuleDesc GetModuleOfType(MetadataType typeDef) 246 { 247 return _explicitScopeMixin.GetModuleOfType(typeDef); 248 } 249 } 250 } 251 252 public struct ReflectableEntity<TEntity> 253 { 254 public readonly TEntity Entity; 255 public readonly MetadataCategory Category; 256 ReflectableEntityILCompiler.ReflectableEntity257 public ReflectableEntity(TEntity entity, MetadataCategory category) 258 { 259 Entity = entity; 260 Category = category; 261 } 262 } 263 } 264