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