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.Collections.Generic; 7 8 using Internal.TypeSystem; 9 10 using ILCompiler.DependencyAnalysis; 11 using ILCompiler.DependencyAnalysisFramework; 12 13 using Debug = System.Diagnostics.Debug; 14 using ReadyToRunSectionType = Internal.Runtime.ReadyToRunSectionType; 15 using ReflectionMapBlob = Internal.Runtime.ReflectionMapBlob; 16 using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList; 17 18 namespace ILCompiler 19 { 20 /// <summary> 21 /// This class is responsible for managing native metadata to be emitted into the compiled 22 /// module. It also helps facilitate mappings between generated runtime structures or code, 23 /// and the native metadata. 24 /// </summary> 25 public abstract class MetadataManager : ICompilationRootProvider 26 { 27 internal const int MetadataOffsetMask = 0xFFFFFF; 28 29 private byte[] _metadataBlob; 30 private List<MetadataMapping<MetadataType>> _typeMappings; 31 private List<MetadataMapping<FieldDesc>> _fieldMappings; 32 private List<MetadataMapping<MethodDesc>> _methodMappings; 33 private List<MetadataMapping<MethodDesc>> _stackTraceMappings; 34 35 protected readonly CompilerTypeSystemContext _typeSystemContext; 36 protected readonly MetadataBlockingPolicy _blockingPolicy; 37 38 private List<NonGCStaticsNode> _cctorContextsGenerated = new List<NonGCStaticsNode>(); 39 private HashSet<TypeDesc> _typesWithEETypesGenerated = new HashSet<TypeDesc>(); 40 private HashSet<TypeDesc> _typesWithConstructedEETypesGenerated = new HashSet<TypeDesc>(); 41 private HashSet<MethodDesc> _methodsGenerated = new HashSet<MethodDesc>(); 42 private HashSet<GenericDictionaryNode> _genericDictionariesGenerated = new HashSet<GenericDictionaryNode>(); 43 private HashSet<IMethodBodyNode> _methodBodiesGenerated = new HashSet<IMethodBodyNode>(); 44 private List<TypeGVMEntriesNode> _typeGVMEntries = new List<TypeGVMEntriesNode>(); 45 private HashSet<DefaultConstructorFromLazyNode> _defaultConstructorsNeeded = new HashSet<DefaultConstructorFromLazyNode>(); 46 47 internal NativeLayoutInfoNode NativeLayoutInfo { get; private set; } 48 internal DynamicInvokeTemplateDataNode DynamicInvokeTemplateData { get; private set; } 49 public virtual bool SupportsReflection => true; 50 MetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy)51 public MetadataManager(CompilerTypeSystemContext typeSystemContext, MetadataBlockingPolicy blockingPolicy) 52 { 53 _typeSystemContext = typeSystemContext; 54 _blockingPolicy = blockingPolicy; 55 } 56 AttachToDependencyGraph(DependencyAnalyzerBase<NodeFactory> graph)57 public void AttachToDependencyGraph(DependencyAnalyzerBase<NodeFactory> graph) 58 { 59 graph.NewMarkedNode += Graph_NewMarkedNode; 60 } 61 BlobIdToReadyToRunSection(ReflectionMapBlob blobId)62 internal static ReadyToRunSectionType BlobIdToReadyToRunSection(ReflectionMapBlob blobId) 63 { 64 var result = (ReadyToRunSectionType)((int)blobId + (int)ReadyToRunSectionType.ReadonlyBlobRegionStart); 65 Debug.Assert(result <= ReadyToRunSectionType.ReadonlyBlobRegionEnd); 66 return result; 67 } 68 AddToReadyToRunHeader(ReadyToRunHeaderNode header, NodeFactory nodeFactory, ExternalReferencesTableNode commonFixupsTableNode)69 public void AddToReadyToRunHeader(ReadyToRunHeaderNode header, NodeFactory nodeFactory, ExternalReferencesTableNode commonFixupsTableNode) 70 { 71 var metadataNode = new MetadataNode(); 72 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.EmbeddedMetadata), metadataNode, metadataNode, metadataNode.EndSymbol); 73 74 var nativeReferencesTableNode = new ExternalReferencesTableNode("NativeReferences", nodeFactory); 75 var nativeStaticsTableNode = new ExternalReferencesTableNode("NativeStatics", nodeFactory); 76 77 var resourceDataNode = new ResourceDataNode(); 78 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.BlobIdResourceData), resourceDataNode, resourceDataNode, resourceDataNode.EndSymbol); 79 80 var resourceIndexNode = new ResourceIndexNode(resourceDataNode); 81 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.BlobIdResourceIndex), resourceIndexNode, resourceIndexNode, resourceIndexNode.EndSymbol); 82 83 var typeMapNode = new TypeMetadataMapNode(commonFixupsTableNode); 84 85 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.TypeMap), typeMapNode, typeMapNode, typeMapNode.EndSymbol); 86 87 var cctorContextMapNode = new ClassConstructorContextMap(commonFixupsTableNode); 88 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.CCtorContextMap), cctorContextMapNode, cctorContextMapNode, cctorContextMapNode.EndSymbol); 89 90 DynamicInvokeTemplateData = new DynamicInvokeTemplateDataNode(commonFixupsTableNode); 91 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.DynamicInvokeTemplateData), DynamicInvokeTemplateData, DynamicInvokeTemplateData, DynamicInvokeTemplateData.EndSymbol); 92 93 var invokeMapNode = new ReflectionInvokeMapNode(commonFixupsTableNode); 94 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.InvokeMap), invokeMapNode, invokeMapNode, invokeMapNode.EndSymbol); 95 96 var arrayMapNode = new ArrayMapNode(commonFixupsTableNode); 97 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.ArrayMap), arrayMapNode, arrayMapNode, arrayMapNode.EndSymbol); 98 99 var fieldMapNode = new ReflectionFieldMapNode(commonFixupsTableNode); 100 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.FieldAccessMap), fieldMapNode, fieldMapNode, fieldMapNode.EndSymbol); 101 102 NativeLayoutInfo = new NativeLayoutInfoNode(nativeReferencesTableNode, nativeStaticsTableNode); 103 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.NativeLayoutInfo), NativeLayoutInfo, NativeLayoutInfo, NativeLayoutInfo.EndSymbol); 104 105 var exactMethodInstantiations = new ExactMethodInstantiationsNode(nativeReferencesTableNode); 106 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.ExactMethodInstantiationsHashtable), exactMethodInstantiations, exactMethodInstantiations, exactMethodInstantiations.EndSymbol); 107 108 var genericsTypesHashtableNode = new GenericTypesHashtableNode(nativeReferencesTableNode); 109 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.GenericsHashtable), genericsTypesHashtableNode, genericsTypesHashtableNode, genericsTypesHashtableNode.EndSymbol); 110 111 var genericMethodsHashtableNode = new GenericMethodsHashtableNode(nativeReferencesTableNode); 112 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.GenericMethodsHashtable), genericMethodsHashtableNode, genericMethodsHashtableNode, genericMethodsHashtableNode.EndSymbol); 113 114 var genericVirtualMethodTableNode = new GenericVirtualMethodTableNode(commonFixupsTableNode); 115 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.GenericVirtualMethodTable), genericVirtualMethodTableNode, genericVirtualMethodTableNode, genericVirtualMethodTableNode.EndSymbol); 116 117 var interfaceGenericVirtualMethodTableNode = new InterfaceGenericVirtualMethodTableNode(commonFixupsTableNode); 118 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.InterfaceGenericVirtualMethodTable), interfaceGenericVirtualMethodTableNode, interfaceGenericVirtualMethodTableNode, interfaceGenericVirtualMethodTableNode.EndSymbol); 119 120 var genericMethodsTemplatesMapNode = new GenericMethodsTemplateMap(commonFixupsTableNode); 121 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.GenericMethodsTemplateMap), genericMethodsTemplatesMapNode, genericMethodsTemplatesMapNode, genericMethodsTemplatesMapNode.EndSymbol); 122 123 var genericTypesTemplatesMapNode = new GenericTypesTemplateMap(commonFixupsTableNode); 124 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.TypeTemplateMap), genericTypesTemplatesMapNode, genericTypesTemplatesMapNode, genericTypesTemplatesMapNode.EndSymbol); 125 126 var blockReflectionTypeMapNode = new BlockReflectionTypeMapNode(commonFixupsTableNode); 127 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.BlockReflectionTypeMap), blockReflectionTypeMapNode, blockReflectionTypeMapNode, blockReflectionTypeMapNode.EndSymbol); 128 129 var staticsInfoHashtableNode = new StaticsInfoHashtableNode(nativeReferencesTableNode, nativeStaticsTableNode); 130 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.StaticsInfoHashtable), staticsInfoHashtableNode, staticsInfoHashtableNode, staticsInfoHashtableNode.EndSymbol); 131 132 var virtualInvokeMapNode = new ReflectionVirtualInvokeMapNode(commonFixupsTableNode); 133 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.VirtualInvokeMap), virtualInvokeMapNode, virtualInvokeMapNode, virtualInvokeMapNode.EndSymbol); 134 135 var defaultConstructorMapNode = new DefaultConstructorMapNode(commonFixupsTableNode); 136 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.DefaultConstructorMap), defaultConstructorMapNode, defaultConstructorMapNode, defaultConstructorMapNode.EndSymbol); 137 138 #if !CORERT 139 var stackTraceEmbeddedMetadataNode = new StackTraceEmbeddedMetadataNode(); 140 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.BlobIdStackTraceEmbeddedMetadata), stackTraceEmbeddedMetadataNode, stackTraceEmbeddedMetadataNode, stackTraceEmbeddedMetadataNode.EndSymbol); 141 #endif 142 143 var stackTraceMethodMappingNode = new StackTraceMethodMappingNode(); 144 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.BlobIdStackTraceMethodRvaToTokenMapping), stackTraceMethodMappingNode, stackTraceMethodMappingNode, stackTraceMethodMappingNode.EndSymbol); 145 146 // The external references tables should go last 147 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.CommonFixupsTable), commonFixupsTableNode, commonFixupsTableNode, commonFixupsTableNode.EndSymbol); 148 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.NativeReferences), nativeReferencesTableNode, nativeReferencesTableNode, nativeReferencesTableNode.EndSymbol); 149 header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.NativeStatics), nativeStaticsTableNode, nativeStaticsTableNode, nativeStaticsTableNode.EndSymbol); 150 } 151 Graph_NewMarkedNode(DependencyNodeCore<NodeFactory> obj)152 protected virtual void Graph_NewMarkedNode(DependencyNodeCore<NodeFactory> obj) 153 { 154 var eetypeNode = obj as EETypeNode; 155 if (eetypeNode != null) 156 { 157 _typesWithEETypesGenerated.Add(eetypeNode.Type); 158 159 if (eetypeNode is ConstructedEETypeNode || eetypeNode is CanonicalEETypeNode) 160 { 161 _typesWithConstructedEETypesGenerated.Add(eetypeNode.Type); 162 } 163 164 return; 165 } 166 167 IMethodBodyNode methodBodyNode = obj as IMethodBodyNode; 168 if (methodBodyNode != null) 169 { 170 _methodBodiesGenerated.Add(methodBodyNode); 171 } 172 173 IMethodNode methodNode = methodBodyNode; 174 if (methodNode == null) 175 methodNode = obj as ShadowConcreteMethodNode; 176 177 if (methodNode != null) 178 { 179 _methodsGenerated.Add(methodNode.Method); 180 return; 181 } 182 183 var reflectableMethodNode = obj as ReflectableMethodNode; 184 if (reflectableMethodNode != null) 185 { 186 _methodsGenerated.Add(reflectableMethodNode.Method); 187 } 188 189 var nonGcStaticSectionNode = obj as NonGCStaticsNode; 190 if (nonGcStaticSectionNode != null && _typeSystemContext.HasLazyStaticConstructor(nonGcStaticSectionNode.Type)) 191 { 192 _cctorContextsGenerated.Add(nonGcStaticSectionNode); 193 } 194 195 var gvmEntryNode = obj as TypeGVMEntriesNode; 196 if (gvmEntryNode != null) 197 { 198 _typeGVMEntries.Add(gvmEntryNode); 199 } 200 201 var dictionaryNode = obj as GenericDictionaryNode; 202 if (dictionaryNode != null) 203 { 204 _genericDictionariesGenerated.Add(dictionaryNode); 205 } 206 207 var ctorFromLazyGenericsNode = obj as DefaultConstructorFromLazyNode; 208 if (ctorFromLazyGenericsNode != null) 209 { 210 _defaultConstructorsNeeded.Add(ctorFromLazyGenericsNode); 211 } 212 } 213 214 /// <summary> 215 /// Is a method that is reflectable a method which should be placed into the invoke map as invokable? 216 /// </summary> IsReflectionInvokable(MethodDesc method)217 public virtual bool IsReflectionInvokable(MethodDesc method) 218 { 219 return IsMethodSignatureSupportedInReflectionInvoke(method) 220 && IsMethodSupportedInReflectionInvoke(method); 221 } 222 IsMethodSignatureSupportedInReflectionInvoke(MethodDesc method)223 protected bool IsMethodSignatureSupportedInReflectionInvoke(MethodDesc method) 224 { 225 var signature = method.Signature; 226 227 // ---------------------------------------------------------------- 228 // TODO: support for methods returning pointer types - https://github.com/dotnet/corert/issues/2113 229 // ---------------------------------------------------------------- 230 231 if (signature.ReturnType.IsPointer) 232 return false; 233 234 for (int i = 0; i < signature.Length; i++) 235 if (signature[i].IsByRef && ((ByRefType)signature[i]).ParameterType.IsPointer) 236 return false; 237 238 // ---------------------------------------------------------------- 239 // TODO: function pointer types are odd: https://github.com/dotnet/corert/issues/1929 240 // ---------------------------------------------------------------- 241 242 if (signature.ReturnType.IsFunctionPointer) 243 return false; 244 245 for (int i = 0; i < signature.Length; i++) 246 if (signature[i].IsFunctionPointer) 247 return false; 248 249 // ---------------------------------------------------------------- 250 // Methods with ByRef returns can't be reflection invoked 251 // ---------------------------------------------------------------- 252 253 if (signature.ReturnType.IsByRef) 254 return false; 255 256 // ---------------------------------------------------------------- 257 // Methods that return ByRef-like types or take them by reference can't be reflection invoked 258 // ---------------------------------------------------------------- 259 260 if (signature.ReturnType.IsByRefLike) 261 return false; 262 263 for (int i = 0; i < signature.Length; i++) 264 { 265 ByRefType paramType = signature[i] as ByRefType; 266 if (paramType != null && paramType.ParameterType.IsByRefLike) 267 return false; 268 } 269 270 return true; 271 } 272 IsMethodSupportedInReflectionInvoke(MethodDesc method)273 protected bool IsMethodSupportedInReflectionInvoke(MethodDesc method) 274 { 275 TypeDesc owningType = method.OwningType; 276 277 // Methods on nullable are special cased in the runtime reflection 278 if (owningType.IsNullable) 279 return false; 280 281 // Finalizers are not reflection invokable 282 if (method.IsFinalizer) 283 return false; 284 285 // Static constructors are not reflection invokable 286 if (method.IsStaticConstructor) 287 return false; 288 289 if (method.IsConstructor) 290 { 291 // Delegate construction is only allowed through specific IL sequences 292 if (owningType.IsDelegate) 293 return false; 294 295 // String constructors are intrinsic and special cased in runtime reflection 296 if (owningType.IsString) 297 return false; 298 } 299 300 // Everything else can go in the mapping table. 301 return true; 302 } 303 304 /// <summary> 305 /// Is there a reflection invoke stub for a method that is invokable? 306 /// </summary> HasReflectionInvokeStub(MethodDesc method)307 public bool HasReflectionInvokeStub(MethodDesc method) 308 { 309 if (!IsReflectionInvokable(method)) 310 return false; 311 312 return HasReflectionInvokeStubForInvokableMethod(method); 313 } 314 315 /// <summary> 316 /// Is there a reflection invoke stub for a method that is invokable? 317 /// </summary> ShouldMethodBeInInvokeMap(MethodDesc method)318 public bool ShouldMethodBeInInvokeMap(MethodDesc method) 319 { 320 // The current format requires us to have an EEType for the owning type. We might want to lift this. 321 if (!TypeGeneratesEEType(method.OwningType)) 322 return false; 323 324 // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail. 325 if (!IsReflectionInvokable(method)) 326 return false; 327 328 return true; 329 } 330 331 /// <summary> 332 /// This method is an extension point that can provide additional metadata-based dependencies to compiled method bodies. 333 /// </summary> GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)334 public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) 335 { 336 MetadataCategory category = GetMetadataCategory(method); 337 338 if ((category & MetadataCategory.Description) != 0) 339 { 340 GetMetadataDependenciesDueToReflectability(ref dependencies, factory, method); 341 } 342 343 if ((category & MetadataCategory.RuntimeMapping) != 0) 344 { 345 if (IsReflectionInvokable(method)) 346 { 347 // We're going to generate a mapping table entry for this. Collect dependencies. 348 CodeBasedDependencyAlgorithm.AddDependenciesDueToReflectability(ref dependencies, factory, method); 349 } 350 } 351 } 352 353 /// <summary> 354 /// This method is an extension point that can provide additional metadata-based dependencies on a virtual method. 355 /// </summary> GetDependenciesDueToVirtualMethodReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)356 public void GetDependenciesDueToVirtualMethodReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) 357 { 358 // If we have a use of an abstract method, GetDependenciesDueToReflectability is not going to see the method 359 // as being used since there's no body. We inject a dependency on a new node that serves as a logical method body 360 // for the metadata manager. Metadata manager treats that node the same as a body. 361 if (method.IsAbstract && GetMetadataCategory(method) != 0) 362 { 363 dependencies = dependencies ?? new DependencyList(); 364 dependencies.Add(factory.ReflectableMethod(method), "Abstract reflectable method"); 365 } 366 } 367 GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)368 protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) 369 { 370 // MetadataManagers can override this to provide additional dependencies caused by the emission of metadata 371 // (E.g. dependencies caused by the method having custom attributes applied to it: making sure we compile the attribute constructor 372 // and property setters) 373 } 374 375 /// <summary> 376 /// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes. 377 /// </summary> GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)378 public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) 379 { 380 MetadataCategory category = GetMetadataCategory(type); 381 382 if ((category & MetadataCategory.Description) != 0) 383 { 384 GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type); 385 } 386 387 if ((category & MetadataCategory.RuntimeMapping) != 0) 388 { 389 // We're going to generate a mapping table entry for this. Collect dependencies. 390 391 // Nothing special is needed for the mapping table (we only emit the EEType and we already 392 // have one, since we got this callback). But check if a child wants to do something extra. 393 GetRuntimeMappingDependenciesDueToReflectability(ref dependencies, factory, type); 394 } 395 } 396 GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)397 protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) 398 { 399 // MetadataManagers can override this to provide additional dependencies caused by the emission of metadata 400 // (E.g. dependencies caused by the type having custom attributes applied to it: making sure we compile the attribute constructor 401 // and property setters) 402 } 403 GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type)404 protected virtual void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) 405 { 406 // MetadataManagers can override this to provide additional dependencies caused by the emission of a runtime 407 // mapping for a type. 408 } 409 410 /// <summary> 411 /// This method is an extension point that can provide additional metadata-based dependencies to generated RuntimeMethodHandles. 412 /// </summary> GetDependenciesDueToLdToken(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)413 public virtual void GetDependenciesDueToLdToken(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) 414 { 415 // MetadataManagers can override this to provide additional dependencies caused by the presence of a 416 // RuntimeMethodHandle data structure. 417 } 418 419 /// <summary> 420 /// This method is an extension point that can provide additional metadata-based dependencies to generated RuntimeFieldHandles. 421 /// </summary> GetDependenciesDueToLdToken(ref DependencyList dependencies, NodeFactory factory, FieldDesc field)422 public virtual void GetDependenciesDueToLdToken(ref DependencyList dependencies, NodeFactory factory, FieldDesc field) 423 { 424 // MetadataManagers can override this to provide additional dependencies caused by the presence of a 425 // RuntimeFieldHandle data structure. 426 } 427 428 /// <summary> 429 /// Given that a method is invokable, does there exist a reflection invoke stub? 430 /// </summary> HasReflectionInvokeStubForInvokableMethod(MethodDesc method)431 public abstract bool HasReflectionInvokeStubForInvokableMethod(MethodDesc method); 432 433 /// <summary> 434 /// Given that a method is invokable, if it is inserted into the reflection invoke table 435 /// will it use a method token to be referenced, or not? 436 /// </summary> WillUseMetadataTokenToReferenceMethod(MethodDesc method)437 public abstract bool WillUseMetadataTokenToReferenceMethod(MethodDesc method); 438 439 /// <summary> 440 /// Given that a method is invokable, if it is inserted into the reflection invoke table 441 /// will it use a field token to be referenced, or not? 442 /// </summary> WillUseMetadataTokenToReferenceField(FieldDesc field)443 public abstract bool WillUseMetadataTokenToReferenceField(FieldDesc field); 444 445 /// <summary> 446 /// Gets a stub that can be used to reflection-invoke a method with a given signature. 447 /// </summary> GetCanonicalReflectionInvokeStub(MethodDesc method)448 public abstract MethodDesc GetCanonicalReflectionInvokeStub(MethodDesc method); 449 450 /// <summary> 451 /// Compute the canonical instantiation of a dynamic invoke thunk needed to invoke a method 452 /// This algorithm is shared with the runtime, so if a thunk requires generic instantiation 453 /// to be used, it must match this algorithm, and cannot be different with different MetadataManagers 454 /// NOTE: This function may return null in cases where an exact instantiation does not exist. (Universal Generics) 455 /// </summary> InstantiateCanonicalDynamicInvokeMethodForMethod(MethodDesc thunk, MethodDesc method)456 protected MethodDesc InstantiateCanonicalDynamicInvokeMethodForMethod(MethodDesc thunk, MethodDesc method) 457 { 458 if (thunk.Instantiation.Length == 0) 459 { 460 // nothing to instantiate 461 return thunk; 462 } 463 464 MethodSignature sig = method.Signature; 465 TypeSystemContext context = method.Context; 466 467 // 468 // Instantiate the generic thunk over the parameters and the return type of the target method 469 // 470 471 ParameterMetadata[] paramMetadata = null; 472 TypeDesc[] instantiation = new TypeDesc[sig.ReturnType.IsVoid ? sig.Length : sig.Length + 1]; 473 Debug.Assert(thunk.Instantiation.Length == instantiation.Length); 474 for (int i = 0; i < sig.Length; i++) 475 { 476 TypeDesc parameterType = sig[i]; 477 if (parameterType.IsByRef) 478 { 479 // strip ByRefType off the parameter (the method already has ByRef in the signature) 480 parameterType = ((ByRefType)parameterType).ParameterType; 481 482 Debug.Assert(!parameterType.IsPointer); // TODO: support for methods returning pointer types - https://github.com/dotnet/corert/issues/2113 483 } 484 else if (parameterType.IsPointer || parameterType.IsFunctionPointer) 485 { 486 // For pointer typed parameters, instantiate the method over IntPtr 487 parameterType = context.GetWellKnownType(WellKnownType.IntPtr); 488 } 489 else if (parameterType.IsEnum) 490 { 491 // If the invoke method takes an enum as an input parameter and there is no default value for 492 // that paramter, we don't need to specialize on the exact enum type (we only need to specialize 493 // on the underlying integral type of the enum.) 494 if (paramMetadata == null) 495 paramMetadata = method.GetParameterMetadata(); 496 497 bool hasDefaultValue = false; 498 foreach (var p in paramMetadata) 499 { 500 // Parameter metadata indexes are 1-based (0 is reserved for return "parameter") 501 if (p.Index == (i + 1) && p.HasDefault) 502 { 503 hasDefaultValue = true; 504 break; 505 } 506 } 507 508 if (!hasDefaultValue) 509 parameterType = parameterType.UnderlyingType; 510 } 511 512 instantiation[i] = parameterType; 513 } 514 515 if (!sig.ReturnType.IsVoid) 516 { 517 TypeDesc returnType = sig.ReturnType; 518 Debug.Assert(!returnType.IsByRef); 519 520 // If the invoke method return an object reference, we don't need to specialize on the 521 // exact type of the object reference, as the behavior is not different. 522 if ((returnType.IsDefType && !returnType.IsValueType) || returnType.IsArray) 523 { 524 returnType = context.GetWellKnownType(WellKnownType.Object); 525 } 526 527 instantiation[sig.Length] = returnType; 528 } 529 530 Debug.Assert(thunk.Instantiation.Length == instantiation.Length); 531 532 // Check if at least one of the instantiation arguments is a universal canonical type, and if so, we 533 // won't create a dynamic invoker instantiation. The arguments will be interpreted at runtime by the 534 // calling convention converter during the dynamic invocation 535 foreach (TypeDesc type in instantiation) 536 { 537 if (type.IsCanonicalSubtype(CanonicalFormKind.Universal)) 538 return null; 539 } 540 541 // If the thunk ends up being shared code, return the canonical method body. 542 // The concrete dictionary for the thunk will be built at runtime and is not interesting for the compiler. 543 Instantiation canonInstantiation = context.ConvertInstantiationToCanonForm(new Instantiation(instantiation), CanonicalFormKind.Specific); 544 545 MethodDesc instantiatedDynamicInvokeMethod = thunk.Context.GetInstantiatedMethod(thunk, canonInstantiation); 546 return instantiatedDynamicInvokeMethod; 547 } 548 EnsureMetadataGenerated(NodeFactory factory)549 protected void EnsureMetadataGenerated(NodeFactory factory) 550 { 551 if (_metadataBlob != null) 552 return; 553 554 ComputeMetadata(factory, out _metadataBlob, out _typeMappings, out _methodMappings, out _fieldMappings, out _stackTraceMappings); 555 } 556 ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider)557 void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider) 558 { 559 // MetadataManagers can override this to provide metadata compilation roots that need to be added to the graph ahead of time. 560 // (E.g. reflection roots computed by IL analyzers, or non-compilation-based roots) 561 } 562 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)563 protected abstract void ComputeMetadata(NodeFactory factory, 564 out byte[] metadataBlob, 565 out List<MetadataMapping<MetadataType>> typeMappings, 566 out List<MetadataMapping<MethodDesc>> methodMappings, 567 out List<MetadataMapping<FieldDesc>> fieldMappings, 568 out List<MetadataMapping<MethodDesc>> stackTraceMapping); 569 570 571 572 /// <summary> 573 /// Returns a set of modules that will get some metadata emitted into the output module 574 /// </summary> GetCompilationModulesWithMetadata()575 public abstract IEnumerable<ModuleDesc> GetCompilationModulesWithMetadata(); 576 GetMetadataBlob(NodeFactory factory)577 public byte[] GetMetadataBlob(NodeFactory factory) 578 { 579 EnsureMetadataGenerated(factory); 580 return _metadataBlob; 581 } 582 GetTypeDefinitionMapping(NodeFactory factory)583 public IEnumerable<MetadataMapping<MetadataType>> GetTypeDefinitionMapping(NodeFactory factory) 584 { 585 EnsureMetadataGenerated(factory); 586 return _typeMappings; 587 } 588 GetMethodMapping(NodeFactory factory)589 public IEnumerable<MetadataMapping<MethodDesc>> GetMethodMapping(NodeFactory factory) 590 { 591 EnsureMetadataGenerated(factory); 592 return _methodMappings; 593 } 594 GetFieldMapping(NodeFactory factory)595 public IEnumerable<MetadataMapping<FieldDesc>> GetFieldMapping(NodeFactory factory) 596 { 597 EnsureMetadataGenerated(factory); 598 return _fieldMappings; 599 } 600 GetStackTraceMapping(NodeFactory factory)601 public IEnumerable<MetadataMapping<MethodDesc>> GetStackTraceMapping(NodeFactory factory) 602 { 603 EnsureMetadataGenerated(factory); 604 return _stackTraceMappings; 605 } 606 GetCctorContextMapping()607 internal IEnumerable<NonGCStaticsNode> GetCctorContextMapping() 608 { 609 return _cctorContextsGenerated; 610 } 611 GetTypeGVMEntries()612 internal IEnumerable<TypeGVMEntriesNode> GetTypeGVMEntries() 613 { 614 return _typeGVMEntries; 615 } 616 GetCompiledGenericDictionaries()617 internal IReadOnlyCollection<GenericDictionaryNode> GetCompiledGenericDictionaries() 618 { 619 return _genericDictionariesGenerated; 620 } 621 GetCompiledMethods()622 internal IEnumerable<MethodDesc> GetCompiledMethods() 623 { 624 return _methodsGenerated; 625 } 626 GetCompiledMethodBodies()627 internal IEnumerable<IMethodBodyNode> GetCompiledMethodBodies() 628 { 629 return _methodBodiesGenerated; 630 } 631 GetDefaultConstructorsNeeded()632 internal IEnumerable<DefaultConstructorFromLazyNode> GetDefaultConstructorsNeeded() 633 { 634 return _defaultConstructorsNeeded; 635 } 636 TypeGeneratesEEType(TypeDesc type)637 internal bool TypeGeneratesEEType(TypeDesc type) 638 { 639 return _typesWithEETypesGenerated.Contains(type); 640 } 641 GetTypesWithEETypes()642 internal IEnumerable<TypeDesc> GetTypesWithEETypes() 643 { 644 return _typesWithEETypesGenerated; 645 } 646 GetTypesWithConstructedEETypes()647 internal IEnumerable<TypeDesc> GetTypesWithConstructedEETypes() 648 { 649 return _typesWithConstructedEETypesGenerated; 650 } 651 IsReflectionBlocked(TypeDesc type)652 public bool IsReflectionBlocked(TypeDesc type) 653 { 654 switch (type.Category) 655 { 656 case TypeFlags.SzArray: 657 case TypeFlags.Array: 658 case TypeFlags.Pointer: 659 case TypeFlags.ByRef: 660 return IsReflectionBlocked(((ParameterizedType)type).ParameterType); 661 662 case TypeFlags.FunctionPointer: 663 throw new NotImplementedException(); 664 665 default: 666 Debug.Assert(type.IsDefType); 667 668 TypeDesc typeDefinition = type.GetTypeDefinition(); 669 if (type != typeDefinition) 670 { 671 if (_blockingPolicy.IsBlocked((MetadataType)typeDefinition)) 672 return true; 673 674 foreach (var arg in type.Instantiation) 675 if (IsReflectionBlocked(arg)) 676 return true; 677 678 return false; 679 } 680 681 if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any)) 682 return false; 683 684 return _blockingPolicy.IsBlocked((MetadataType)type); 685 } 686 } 687 IsReflectionBlocked(Instantiation instantiation)688 protected bool IsReflectionBlocked(Instantiation instantiation) 689 { 690 foreach (TypeDesc type in instantiation) 691 { 692 if (IsReflectionBlocked(type)) 693 return true; 694 } 695 return false; 696 } 697 IsReflectionBlocked(FieldDesc field)698 public bool IsReflectionBlocked(FieldDesc field) 699 { 700 FieldDesc typicalFieldDefinition = field.GetTypicalFieldDefinition(); 701 if (typicalFieldDefinition != field && IsReflectionBlocked(field.OwningType.Instantiation)) 702 { 703 return true; 704 } 705 706 return _blockingPolicy.IsBlocked(typicalFieldDefinition); 707 } 708 IsReflectionBlocked(MethodDesc method)709 public bool IsReflectionBlocked(MethodDesc method) 710 { 711 MethodDesc methodDefinition = method.GetMethodDefinition(); 712 if (method != methodDefinition && IsReflectionBlocked(method.Instantiation)) 713 { 714 return true; 715 } 716 717 MethodDesc typicalMethodDefinition = methodDefinition.GetTypicalMethodDefinition(); 718 if (typicalMethodDefinition != methodDefinition && IsReflectionBlocked(method.OwningType.Instantiation)) 719 { 720 return true; 721 } 722 723 return _blockingPolicy.IsBlocked(typicalMethodDefinition); 724 } 725 CanGenerateMetadata(MetadataType type)726 public bool CanGenerateMetadata(MetadataType type) 727 { 728 return (GetMetadataCategory(type) & MetadataCategory.Description) != 0; 729 } 730 CanGenerateMetadata(MethodDesc method)731 public bool CanGenerateMetadata(MethodDesc method) 732 { 733 Debug.Assert(method.IsTypicalMethodDefinition); 734 return (GetMetadataCategory(method) & MetadataCategory.Description) != 0; 735 } 736 CanGenerateMetadata(FieldDesc field)737 public bool CanGenerateMetadata(FieldDesc field) 738 { 739 Debug.Assert(field.IsTypicalFieldDefinition); 740 return (GetMetadataCategory(field) & MetadataCategory.Description) != 0; 741 } 742 743 /// <summary> 744 /// Gets the metadata category for a compiled method body in the current compilation. 745 /// The method will only get called with '<paramref name="method"/>' that has a compiled method body 746 /// in this compilation. 747 /// Note that if this method doesn't return <see cref="MetadataCategory.Description"/>, it doesn't mean 748 /// that the method never has metadata. The metadata might just be generated in a different compilation. 749 /// </summary> GetMetadataCategory(MethodDesc method)750 protected abstract MetadataCategory GetMetadataCategory(MethodDesc method); 751 752 /// <summary> 753 /// Gets the metadata category for a generated type in the current compilation. 754 /// The method can assume it will only get called with '<paramref name="type"/>' that has an EEType generated 755 /// in the current compilation. 756 /// Note that if this method doesn't return <see cref="MetadataCategory.Description"/>, it doesn't mean 757 /// that the method never has metadata. The metadata might just be generated in a different compilation. 758 /// </summary> GetMetadataCategory(TypeDesc type)759 protected abstract MetadataCategory GetMetadataCategory(TypeDesc type); GetMetadataCategory(FieldDesc field)760 protected abstract MetadataCategory GetMetadataCategory(FieldDesc field); 761 } 762 763 public struct MetadataMapping<TEntity> 764 { 765 public readonly TEntity Entity; 766 public readonly int MetadataHandle; 767 MetadataMappingILCompiler.MetadataMapping768 public MetadataMapping(TEntity entity, int metadataHandle) 769 { 770 Entity = entity; 771 MetadataHandle = metadataHandle; 772 } 773 } 774 775 [Flags] 776 public enum MetadataCategory 777 { 778 None = 0x00, 779 Description = 0x01, 780 RuntimeMapping = 0x02, 781 } 782 } 783