df28255b46025db7a922942c3afc55cac181462e
[platform/upstream/dotnet/runtime.git] /
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
4 using global::System;
5 using global::System.Reflection;
6 using global::System.Collections.Generic;
7
8 using global::Internal.Runtime.Augments;
9 using global::Internal.Runtime.CompilerServices;
10 using global::Internal.Runtime.TypeLoader;
11
12 using global::Internal.Reflection.Core.Execution;
13 using global::Internal.Reflection.Execution.MethodInvokers;
14 using global::Internal.Reflection.Execution.FieldAccessors;
15
16 using global::Internal.Metadata.NativeFormat;
17
18 using global::System.Runtime.InteropServices;
19
20 using global::Internal.Runtime;
21 using global::Internal.NativeFormat;
22
23 using System.Reflection.Runtime.General;
24 using System.Threading;
25
26 using CanonicalFormKind = global::Internal.TypeSystem.CanonicalFormKind;
27
28
29 using Debug = System.Diagnostics.Debug;
30
31 namespace Internal.Reflection.Execution
32 {
33     //==========================================================================================================
34     // These ExecutionEnvironment entrypoints provide access to the NUTC-generated blob information that
35     // enables Reflection invoke and tie-ins to native Type artifacts.
36     //
37     // - Except when otherwise noted, ExecutionEnvironment methods use the "TryGet*" pattern rather than throwing exceptions.
38     //
39     // - All methods on this class must be multi-thread-safe. Reflection can and does invoke them on different threads with no synchronization of its own.
40     //
41     //==========================================================================================================
42     internal sealed partial class ExecutionEnvironmentImplementation : ExecutionEnvironment
43     {
44         private static RuntimeTypeHandle GetOpenTypeDefinition(RuntimeTypeHandle typeHandle, out RuntimeTypeHandle[] typeArgumentsHandles)
45         {
46             if (RuntimeAugments.IsGenericType(typeHandle))
47             {
48                 return RuntimeAugments.GetGenericInstantiation(typeHandle, out typeArgumentsHandles);
49             }
50
51             typeArgumentsHandles = null;
52             return typeHandle;
53         }
54
55         private static RuntimeTypeHandle GetTypeDefinition(RuntimeTypeHandle typeHandle)
56         {
57             if (RuntimeAugments.IsGenericType(typeHandle))
58                 return RuntimeAugments.GetGenericDefinition(typeHandle);
59
60             return typeHandle;
61         }
62
63         private static bool RuntimeTypeHandleIsNonDefault(RuntimeTypeHandle runtimeTypeHandle)
64         {
65             return ((IntPtr)RuntimeAugments.GetPointerFromTypeHandle(runtimeTypeHandle)) != IntPtr.Zero;
66         }
67
68         private static unsafe NativeReader GetNativeReaderForBlob(NativeFormatModuleInfo module, ReflectionMapBlob blob)
69         {
70             NativeReader reader;
71             if (TryGetNativeReaderForBlob(module, blob, out reader))
72             {
73                 return reader;
74             }
75
76             Debug.Assert(false);
77             return default(NativeReader);
78         }
79
80         private static unsafe bool TryGetNativeReaderForBlob(NativeFormatModuleInfo module, ReflectionMapBlob blob, out NativeReader reader)
81         {
82             byte* pBlob;
83             uint cbBlob;
84
85             if (module.TryFindBlob((int)blob, out pBlob, out cbBlob))
86             {
87                 reader = new NativeReader(pBlob, cbBlob);
88                 return true;
89             }
90
91             reader = default(NativeReader);
92             return false;
93         }
94
95         /// <summary>
96         /// Return the metadata handle for a TypeDef if the pay-for-policy enabled this type as browsable. This is used to obtain name and other information for types
97         /// obtained via typeof() or Object.GetType(). This can include generic types (not to be confused with generic instances).
98         ///
99         /// Preconditions:
100         ///    runtimeTypeHandle is a typedef (not a constructed type such as an array or generic instance.)
101         /// </summary>
102         /// <param name="runtimeTypeHandle">Runtime handle of the type in question</param>
103         /// <param name="qTypeDefinition">TypeDef handle for the type</param>
104         public sealed override unsafe bool TryGetMetadataForNamedType(RuntimeTypeHandle runtimeTypeHandle, out QTypeDefinition qTypeDefinition)
105         {
106             Debug.Assert(!RuntimeAugments.IsGenericType(runtimeTypeHandle));
107             return TypeLoaderEnvironment.Instance.TryGetMetadataForNamedType(runtimeTypeHandle, out qTypeDefinition);
108         }
109
110         //
111         // Return true for a TypeDef if the policy has decided this type is blocked from reflection.
112         //
113         // Preconditions:
114         //    runtimeTypeHandle is a typedef or a generic type instance (not a constructed type such as an array)
115         //
116         public sealed override unsafe bool IsReflectionBlocked(RuntimeTypeHandle runtimeTypeHandle)
117         {
118             // For generic types, use the generic type definition
119             runtimeTypeHandle = GetTypeDefinition(runtimeTypeHandle);
120             var moduleHandle = RuntimeAugments.GetModuleFromTypeHandle(runtimeTypeHandle);
121
122             //make sure the module is actually NativeFormatModuleInfo, if the module
123             //doesnt have reflection enabled it wont be a NativeFormatModuleInfo
124             if (!(ModuleList.Instance.TryGetModuleInfoByHandle(moduleHandle, out ModuleInfo untypedModuleInfo) && (untypedModuleInfo is NativeFormatModuleInfo module)))
125             {
126                 return true;
127             }
128
129             NativeReader blockedReflectionReader = GetNativeReaderForBlob(module, ReflectionMapBlob.BlockReflectionTypeMap);
130             NativeParser blockedReflectionParser = new NativeParser(blockedReflectionReader, 0);
131             NativeHashtable blockedReflectionHashtable = new NativeHashtable(blockedReflectionParser);
132             ExternalReferencesTable externalReferences = default(ExternalReferencesTable);
133             externalReferences.InitializeCommonFixupsTable(module);
134
135             int hashcode = runtimeTypeHandle.GetHashCode();
136             var lookup = blockedReflectionHashtable.Lookup(hashcode);
137             NativeParser entryParser;
138             while (!(entryParser = lookup.GetNext()).IsNull)
139             {
140                 RuntimeTypeHandle entryType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
141                 if (!entryType.Equals(runtimeTypeHandle))
142                     continue;
143
144                 // Entry found, must be blocked
145                 return true;
146             }
147             // Entry not found, must not be blocked
148             return false;
149         }
150
151         /// <summary>
152         /// Return the RuntimeTypeHandle for the named type described in metadata. This is used to implement the Create and Invoke
153         /// apis for types.
154         ///
155         /// Preconditions:
156         ///    metadataReader + typeDefHandle  - a valid metadata reader + typeDefinitionHandle where "metadataReader" is one
157         ///                                      of the metadata readers returned by ExecutionEnvironment.MetadataReaders.
158         ///
159         /// Note: Although this method has a "bool" return value like the other mapping table accessors, the Project N pay-for-play design
160         /// guarantees that any type enabled for metadata also has a RuntimeTypeHandle underneath.
161         /// </summary>
162         /// <param name="qTypeDefinition">TypeDef handle for the type to look up</param>
163         /// <param name="runtimeTypeHandle">Runtime type handle (MethodTable) for the given type</param>
164         public sealed override unsafe bool TryGetNamedTypeForMetadata(QTypeDefinition qTypeDefinition, out RuntimeTypeHandle runtimeTypeHandle)
165         {
166             return TypeLoaderEnvironment.Instance.TryGetNamedTypeForMetadata(qTypeDefinition, out runtimeTypeHandle);
167         }
168
169         /// <summary>
170         /// Return the metadata handle for a TypeRef if this type was referenced indirectly by other type that pay-for-play has denoted as browsable
171         /// (for example, as part of a method signature.)
172         ///
173         /// This is only used in "debug" builds to provide better missing metadata diagnostics.
174         ///
175         /// Preconditions:
176         ///    runtimeTypeHandle is a typedef (not a constructed type such as an array or generic instance.)
177         /// </summary>
178         /// <param name="runtimeTypeHandle">MethodTable of the type in question</param>
179         /// <param name="metadataReader">Metadata reader for the type</param>
180         /// <param name="typeRefHandle">Located TypeRef handle</param>
181         public sealed override unsafe bool TryGetTypeReferenceForNamedType(RuntimeTypeHandle runtimeTypeHandle, out MetadataReader metadataReader, out TypeReferenceHandle typeRefHandle)
182         {
183             return TypeLoaderEnvironment.TryGetTypeReferenceForNamedType(runtimeTypeHandle, out metadataReader, out typeRefHandle);
184         }
185
186         /// <summary>
187         /// Return the RuntimeTypeHandle for the named type referenced by another type that pay-for-play denotes as browsable (for example,
188         /// in a member signature.) Typically, the type itself is *not* browsable (or it would have appeared in the TypeDef table.)
189         ///
190         /// This is used to ensure that we can produce a Type object if requested and that it match up with the analogous
191         /// Type obtained via typeof().
192         ///
193         ///
194         /// Preconditions:
195         ///    metadataReader + typeRefHandle  - a valid metadata reader + typeReferenceHandle where "metadataReader" is one
196         ///                                      of the metadata readers returned by ExecutionEnvironment.MetadataReaders.
197         ///
198         /// Note: Although this method has a "bool" return value like the other mapping table accessors, the pay-for-play design
199         /// guarantees that any type that has a metadata TypeReference to it also has a RuntimeTypeHandle underneath.
200         /// </summary>
201         /// <param name="metadataReader">Metadata reader for module containing the type reference</param>
202         /// <param name="typeRefHandle">TypeRef handle to look up</param>
203         /// <param name="runtimeTypeHandle">Resolved MethodTable for the type reference</param>
204         public sealed override unsafe bool TryGetNamedTypeForTypeReference(MetadataReader metadataReader, TypeReferenceHandle typeRefHandle, out RuntimeTypeHandle runtimeTypeHandle)
205         {
206             return TypeLoaderEnvironment.TryGetNamedTypeForTypeReference(metadataReader, typeRefHandle, out runtimeTypeHandle);
207         }
208
209         //
210         // Given a RuntimeTypeHandle for any type E, return a RuntimeTypeHandle for type E[], if the pay for play policy denotes E[] as browsable. This is used to
211         // implement Array.CreateInstance().
212         //
213         // Preconditions:
214         //     elementTypeHandle is a valid RuntimeTypeHandle.
215         //
216         // This is not equivalent to calling TryGetMultiDimTypeForElementType() with a rank of 1!
217         //
218         public sealed override unsafe bool TryGetArrayTypeForElementType(RuntimeTypeHandle elementTypeHandle, out RuntimeTypeHandle arrayTypeHandle)
219         {
220             if (RuntimeAugments.IsGenericTypeDefinition(elementTypeHandle))
221             {
222                 arrayTypeHandle = default(RuntimeTypeHandle);
223                 return false;
224             }
225
226             // For non-dynamic arrays try to look up the array type in the ArrayMap blobs;
227             // attempt to dynamically create a new one if that doesn't succeed.
228             return TypeLoaderEnvironment.Instance.TryGetArrayTypeForElementType(elementTypeHandle, false, -1, out arrayTypeHandle);
229         }
230
231         //
232         // Given a RuntimeTypeHandle for any array type E[], return a RuntimeTypeHandle for type E, if the pay for play policy denoted E[] as browsable.
233         //
234         // Preconditions:
235         //      arrayTypeHandle is a valid RuntimeTypeHandle of type array.
236         //
237         // This is not equivalent to calling TryGetMultiDimTypeElementType() with a rank of 1!
238         //
239         public sealed override unsafe bool TryGetArrayTypeElementType(RuntimeTypeHandle arrayTypeHandle, out RuntimeTypeHandle elementTypeHandle)
240         {
241             elementTypeHandle = RuntimeAugments.GetRelatedParameterTypeHandle(arrayTypeHandle);
242             return true;
243         }
244
245
246         //
247         // Given a RuntimeTypeHandle for any type E, return a RuntimeTypeHandle for type E[,,], if the pay for policy denotes E[,,] as browsable. This is used to
248         // implement Type.MakeArrayType(Type, int).
249         //
250         // Preconditions:
251         //     elementTypeHandle is a valid RuntimeTypeHandle.
252         //
253         // Calling this with rank 1 is not equivalent to calling TryGetArrayTypeForElementType()!
254         //
255         public sealed override unsafe bool TryGetMultiDimArrayTypeForElementType(RuntimeTypeHandle elementTypeHandle, int rank, out RuntimeTypeHandle arrayTypeHandle)
256         {
257             if (RuntimeAugments.IsGenericTypeDefinition(elementTypeHandle))
258             {
259                 arrayTypeHandle = default(RuntimeTypeHandle);
260                 return false;
261             }
262
263             if ((rank < MDArray.MinRank) || (rank > MDArray.MaxRank))
264             {
265                 throw new TypeLoadException(SR.Format(SR.MultiDim_Of_This_Rank_Not_Supported, rank));
266             }
267
268             return TypeLoaderEnvironment.Instance.TryGetArrayTypeForElementType(elementTypeHandle, true, rank, out arrayTypeHandle);
269         }
270
271         //
272         // Given a RuntimeTypeHandle for any type E, return a RuntimeTypeHandle for type E*, if the pay-for-play policy denotes E* as browsable. This is used to
273         // ensure that "typeof(E*)" and "typeof(E).MakePointerType()" returns the same Type object.
274         //
275         // Preconditions:
276         //     targetTypeHandle is a valid RuntimeTypeHandle.
277         //
278         public sealed override unsafe bool TryGetPointerTypeForTargetType(RuntimeTypeHandle targetTypeHandle, out RuntimeTypeHandle pointerTypeHandle)
279         {
280             return TypeLoaderEnvironment.Instance.TryGetPointerTypeForTargetType(targetTypeHandle, out pointerTypeHandle);
281         }
282
283         //
284         // Given a RuntimeTypeHandle for any pointer type E*, return a RuntimeTypeHandle for type E, if the pay-for-play policy denotes E* as browsable.
285         // This is used to implement Type.GetElementType() for pointers.
286         //
287         // Preconditions:
288         //      pointerTypeHandle is a valid RuntimeTypeHandle of type pointer.
289         //
290         public sealed override unsafe bool TryGetPointerTypeTargetType(RuntimeTypeHandle pointerTypeHandle, out RuntimeTypeHandle targetTypeHandle)
291         {
292             targetTypeHandle = RuntimeAugments.GetRelatedParameterTypeHandle(pointerTypeHandle);
293             return true;
294         }
295
296         //
297         // Given a RuntimeTypeHandle for any type E, return a RuntimeTypeHandle for type E&, if the pay-for-play policy denotes E& as browsable. This is used to
298         // ensure that "typeof(E&)" and "typeof(E).MakeByRefType()" returns the same Type object.
299         //
300         // Preconditions:
301         //     targetTypeHandle is a valid RuntimeTypeHandle.
302         //
303         public sealed override unsafe bool TryGetByRefTypeForTargetType(RuntimeTypeHandle targetTypeHandle, out RuntimeTypeHandle byRefTypeHandle)
304         {
305             return TypeLoaderEnvironment.Instance.TryGetByRefTypeForTargetType(targetTypeHandle, out byRefTypeHandle);
306         }
307
308         //
309         // Given a RuntimeTypeHandle for any byref type E&, return a RuntimeTypeHandle for type E, if the pay-for-play policy denotes E& as browsable.
310         // This is used to implement Type.GetElementType() for byrefs.
311         //
312         // Preconditions:
313         //      byRefTypeHandle is a valid RuntimeTypeHandle of a byref.
314         //
315         public sealed override unsafe bool TryGetByRefTypeTargetType(RuntimeTypeHandle byRefTypeHandle, out RuntimeTypeHandle targetTypeHandle)
316         {
317             targetTypeHandle = RuntimeAugments.GetRelatedParameterTypeHandle(byRefTypeHandle);
318             return true;
319         }
320
321         //
322         // Given a RuntimeTypeHandle for a generic type G and a set of RuntimeTypeHandles T1, T2.., return the RuntimeTypeHandle for the generic
323         // instance G<T1,T2...> if the pay-for-play policy denotes G<T1,T2...> as browsable. This is used to implement Type.MakeGenericType().
324         //
325         // Preconditions:
326         //      runtimeTypeDefinitionHandle is a valid RuntimeTypeHandle for a generic type.
327         //      genericTypeArgumentHandles is an array of valid RuntimeTypeHandles.
328         //
329         public sealed override unsafe bool TryGetConstructedGenericTypeForComponents(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle)
330         {
331             if (TypeLoaderEnvironment.Instance.TryLookupConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out runtimeTypeHandle))
332             {
333                 return true;
334             }
335
336             Type typeDefinition = Type.GetTypeFromHandle(genericTypeDefinitionHandle);
337
338             Type[] typeArguments = new Type[genericTypeArgumentHandles.Length];
339             for (int i = 0; i < genericTypeArgumentHandles.Length; i++)
340             {
341                 // Early out if one of the arguments is a generic definition.
342                 // The reflection stack will use this to construct a Type that doesn't have a type handle.
343                 // Note: this is different from the validation we do in EnsureSatisfiesClassConstraints because this
344                 // should not throw.
345                 if (RuntimeAugments.IsGenericTypeDefinition(genericTypeArgumentHandles[i]))
346                     return false;
347
348                 typeArguments[i] = Type.GetTypeFromHandle(genericTypeArgumentHandles[i]);
349             }
350
351             ConstraintValidator.EnsureSatisfiesClassConstraints(typeDefinition, typeArguments);
352
353             return TypeLoaderEnvironment.Instance.TryGetConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out runtimeTypeHandle);
354         }
355
356
357         // Given a RuntimeTypeHandle for a generic type G and a set of RuntimeTypeHandles T1, T2.., return the RuntimeTypeHandle for the generic
358         // instance G<T1,T2...> if the pay-for-play policy denotes G<T1,T2...> as browsable. This is used to implement Type.MakeGenericType().
359         //
360         // Preconditions:
361         //      runtimeTypeDefinitionHandle is a valid RuntimeTypeHandle for a generic type.
362         //      genericTypeArgumentHandles is an array of valid RuntimeTypeHandles.
363         //
364         public sealed override unsafe bool TryGetConstructedGenericTypeForComponentsNoConstraintCheck(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle)
365         {
366             return TypeLoaderEnvironment.Instance.TryGetConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out runtimeTypeHandle);
367         }
368
369         public sealed override MethodInvoker TryGetMethodInvoker(RuntimeTypeHandle declaringTypeHandle, QMethodDefinition methodHandle, RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
370         {
371             MethodBase methodInfo = ReflectionCoreExecution.ExecutionDomain.GetMethod(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles);
372
373             // Validate constraints first. This is potentially useless work if the method already exists, but it prevents bad
374             // inputs to reach the type loader (we don't have support to e.g. represent pointer types within the type loader)
375             if (genericMethodTypeArgumentHandles != null && genericMethodTypeArgumentHandles.Length > 0)
376                 ConstraintValidator.EnsureSatisfiesClassConstraints((MethodInfo)methodInfo);
377
378             MethodSignatureComparer methodSignatureComparer = new MethodSignatureComparer(methodHandle);
379
380             MethodInvokeInfo methodInvokeInfo;
381 #if GENERICS_FORCE_USG
382             // Stress mode to force the usage of universal canonical method targets for reflection invokes.
383             // It is recommended to use "/SharedGenericsMode GenerateAllUniversalGenerics" NUTC command line argument when
384             // compiling the application in order to effectively use the GENERICS_FORCE_USG mode.
385
386             // If we are just trying to invoke a non-generic method on a non-generic type, we won't force the universal lookup
387             if (!RuntimeAugments.IsGenericType(declaringTypeHandle) && (genericMethodTypeArgumentHandles == null || genericMethodTypeArgumentHandles.Length == 0))
388                 methodInvokeInfo = TryGetMethodInvokeInfo(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles,
389                     methodInfo, ref methodSignatureComparer, CanonicalFormKind.Specific);
390             else
391                 methodInvokeInfo = TryGetMethodInvokeInfo(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles,
392                     methodInfo, ref methodSignatureComparer, CanonicalFormKind.Universal);
393 #else
394             methodInvokeInfo = TryGetMethodInvokeInfo(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles,
395                 methodInfo, ref methodSignatureComparer, CanonicalFormKind.Specific);
396
397             // If we failed to get a MethodInvokeInfo for an exact method, or a canonically equivalent method, check if there is a universal canonically
398             // equivalent entry that could be used (it will be much slower, and require a calling convention converter)
399             methodInvokeInfo ??= TryGetMethodInvokeInfo(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles,
400                     methodInfo, ref methodSignatureComparer, CanonicalFormKind.Universal);
401 #endif
402
403             if (methodInvokeInfo == null)
404                 return null;
405
406             return MethodInvokerWithMethodInvokeInfo.CreateMethodInvoker(declaringTypeHandle, methodHandle, methodInvokeInfo);
407         }
408
409         //
410         // Get the pointer of a dynamic method invocation thunk
411         //
412         private static IntPtr GetDynamicMethodInvoke(NativeFormatModuleInfo module, uint cookie)
413         {
414             ExternalReferencesTable extRefs = default(ExternalReferencesTable);
415             extRefs.InitializeCommonFixupsTable(module);
416
417             return extRefs.GetFunctionPointerFromIndex(cookie);
418         }
419
420         private static RuntimeTypeHandle[] GetTypeSequence(ref ExternalReferencesTable extRefs, ref NativeParser parser)
421         {
422             uint count = parser.GetUnsigned();
423             RuntimeTypeHandle[] result = new RuntimeTypeHandle[count];
424             for (uint i = 0; i < count; i++)
425             {
426                 result[i] = extRefs.GetRuntimeTypeHandleFromIndex(parser.GetUnsigned());
427             }
428             return result;
429         }
430
431         private static IntPtr TryGetVirtualResolveData(NativeFormatModuleInfo module,
432             RuntimeTypeHandle methodHandleDeclaringType, QMethodDefinition methodHandle, RuntimeTypeHandle[] genericArgs,
433             ref MethodSignatureComparer methodSignatureComparer)
434         {
435             TypeLoaderEnvironment.VirtualResolveDataResult lookupResult;
436             bool success = TypeLoaderEnvironment.TryGetVirtualResolveData(module, methodHandleDeclaringType, genericArgs, ref methodSignatureComparer, out lookupResult);
437             if (!success)
438                 return IntPtr.Zero;
439             else
440             {
441                 GCHandle reader = Internal.TypeSystem.LockFreeObjectInterner.GetInternedObjectHandle(methodHandle.Reader);
442
443                 if (lookupResult.IsGVM)
444                 {
445                     return (new OpenMethodResolver(lookupResult.DeclaringInvokeType, lookupResult.GVMHandle, reader, methodHandle.Token)).ToIntPtr();
446                 }
447                 else
448                 {
449                     return (new OpenMethodResolver(lookupResult.DeclaringInvokeType, lookupResult.SlotIndex, reader, methodHandle.Token)).ToIntPtr();
450                 }
451             }
452         }
453
454         /// <summary>
455         /// Try to look up method invoke info in metadata for all registered modules, construct
456         /// the calling convention converter as appropriate and fill in MethodInvokeInfo.
457         /// </summary>
458         /// <param name="declaringTypeHandle">Runtime handle of declaring type for the method</param>
459         /// <param name="methodHandle">Handle of method to look up</param>
460         /// <param name="genericMethodTypeArgumentHandles">Runtime handles of generic method arguments</param>
461         /// <param name="methodInfo">MethodInfo of method to look up</param>
462         /// <param name="methodSignatureComparer">Helper structure used for comparing signatures</param>
463         /// <param name="canonFormKind">Requested canon form</param>
464         /// <returns>Constructed method invoke info, null on failure</returns>
465         private static unsafe MethodInvokeInfo TryGetMethodInvokeInfo(
466             RuntimeTypeHandle declaringTypeHandle,
467             QMethodDefinition methodHandle,
468             RuntimeTypeHandle[] genericMethodTypeArgumentHandles,
469             MethodBase methodInfo,
470             ref MethodSignatureComparer methodSignatureComparer,
471             CanonicalFormKind canonFormKind)
472         {
473             MethodInvokeMetadata methodInvokeMetadata;
474
475             if (!TypeLoaderEnvironment.TryGetMethodInvokeMetadata(
476                 declaringTypeHandle,
477                 methodHandle,
478                 genericMethodTypeArgumentHandles,
479                 ref methodSignatureComparer,
480                 canonFormKind,
481                 out methodInvokeMetadata))
482             {
483                 // Method invoke info not found
484                 return null;
485             }
486
487             if ((methodInvokeMetadata.InvokeTableFlags & InvokeTableFlags.CallingConventionMask) != 0)
488             {
489                 // MethodInvokeInfo found, but it references a method with a native calling convention.
490                 return null;
491             }
492
493             IntPtr dynamicInvokeMethod;
494             Debug.Assert((methodInvokeMetadata.InvokeTableFlags & InvokeTableFlags.NeedsParameterInterpretation) == 0);
495             dynamicInvokeMethod = GetDynamicMethodInvoke(
496                 methodInvokeMetadata.MappingTableModule,
497                 methodInvokeMetadata.DynamicInvokeCookie);
498
499             IntPtr resolver = IntPtr.Zero;
500             if ((methodInvokeMetadata.InvokeTableFlags & InvokeTableFlags.HasVirtualInvoke) != 0)
501             {
502                 resolver = TryGetVirtualResolveData(ModuleList.Instance.GetModuleInfoForMetadataReader(methodHandle.NativeFormatReader),
503                     declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles,
504                     ref methodSignatureComparer);
505
506                 // Unable to find virtual resolution information, cannot return valid MethodInvokeInfo
507                 if (resolver == IntPtr.Zero)
508                     return null;
509             }
510
511             var methodInvokeInfo = new MethodInvokeInfo(methodInfo, dynamicInvokeMethod)
512             {
513                 LdFtnResult = methodInvokeMetadata.MethodEntryPoint,
514                 VirtualResolveData = resolver,
515             };
516             return methodInvokeInfo;
517         }
518
519         private static RuntimeTypeHandle GetExactDeclaringType(RuntimeTypeHandle dstType, RuntimeTypeHandle srcType)
520         {
521             // The fact that for generic types we rely solely on the template type in the mapping table causes
522             // trouble for lookups from method pointer to the declaring type and method metadata handle.
523
524             // Suppose we have following code:
525             // class Base<T> { void Frob() { } }
526             // class Derived<T> : Base<T> { }
527             // Let's pick Base<object>, Derived<object> as the template.
528             // Now if someone calls TryGetMethodForOriginalLdFtnResult with a pointer to the Frob method and a RuntimeTypeHandle
529             // of the Derived<string> object instance, we are expected to return the metadata handle for Frob with *Base*<string>
530             // as the declaring type. The table obviously only has an entry for Frob with Base<object>.
531
532             // This method needs to return "true" and "Base<string>" for cases like this.
533
534             RuntimeTypeHandle dstTypeDef = GetTypeDefinition(dstType);
535
536             while (!srcType.IsNull())
537             {
538                 if (RuntimeAugments.IsAssignableFrom(dstType, srcType))
539                 {
540                     return dstType;
541                 }
542
543                 if (!dstTypeDef.IsNull() && RuntimeAugments.IsGenericType(srcType))
544                 {
545                     RuntimeTypeHandle srcTypeDef = GetTypeDefinition(srcType);;
546
547                     // Compare TypeDefs. We don't look at the generic components. We already know that the right type
548                     // to return must be somewhere in the inheritance chain.
549                     if (dstTypeDef.Equals(srcTypeDef))
550                     {
551                         // Return the *other* type handle since dstType is instantiated over different arguments
552                         return srcType;
553                     }
554                 }
555
556                 if (!RuntimeAugments.TryGetBaseType(srcType, out srcType))
557                 {
558                     break;
559                 }
560             }
561
562             Debug.Assert(false);
563             return default(RuntimeTypeHandle);
564         }
565
566         private struct FunctionPointerOffsetPair : IComparable<FunctionPointerOffsetPair>
567         {
568             public FunctionPointerOffsetPair(IntPtr functionPointer, uint offset)
569             {
570                 FunctionPointer = functionPointer;
571                 Offset = offset;
572             }
573
574             public int CompareTo(FunctionPointerOffsetPair other)
575             {
576                 unsafe
577                 {
578                     void* fptr = FunctionPointer.ToPointer();
579                     void* otherFptr = other.FunctionPointer.ToPointer();
580
581                     if (fptr < otherFptr)
582                         return -1;
583                     else if (fptr == otherFptr)
584                         return Offset.CompareTo(other.Offset);
585                     else
586                         return 1;
587                 }
588             }
589
590             public readonly IntPtr FunctionPointer;
591             public readonly uint Offset;
592         }
593
594         private struct FunctionPointersToOffsets
595         {
596             public FunctionPointerOffsetPair[] Data;
597
598             public bool TryGetOffsetsRange(IntPtr functionPointer, out int firstParserOffsetIndex, out int lastParserOffsetIndex)
599             {
600                 firstParserOffsetIndex = -1;
601                 lastParserOffsetIndex = -1;
602
603                 if (Data == null)
604                     return false;
605
606                 int binarySearchIndex = Array.BinarySearch(Data, new FunctionPointerOffsetPair(functionPointer, 0));
607
608                 // Array.BinarySearch will return either a positive number which is the first index in a range
609                 // or a negative number which is the bitwise complement of the start of the range
610                 // or a negative number which doesn't correspond to the range at all.
611                 if (binarySearchIndex < 0)
612                     binarySearchIndex = ~binarySearchIndex;
613
614                 if (binarySearchIndex >= Data.Length || Data[binarySearchIndex].FunctionPointer != functionPointer)
615                     return false;
616
617                 // binarySearchIndex now contains the index of the start of a range of matching function pointers and offsets
618                 firstParserOffsetIndex = binarySearchIndex;
619                 lastParserOffsetIndex = binarySearchIndex;
620                 while ((lastParserOffsetIndex < (Data.Length - 1)) && Data[lastParserOffsetIndex + 1].FunctionPointer == functionPointer)
621                 {
622                     lastParserOffsetIndex++;
623                 }
624                 return true;
625             }
626         }
627
628         // ldftn reverse lookup hash. Must be cleared and reset if the module list changes. (All sets to
629         // this variable must happen under a lock)
630         private volatile KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>[] _ldftnReverseLookup_InvokeMap;
631         private Func<NativeFormatModuleInfo, FunctionPointersToOffsets> _computeLdFtnLookupInvokeMapInvokeMap = ComputeLdftnReverseLookup_InvokeMap;
632
633         /// <summary>
634         /// Initialize a lookup array of module to function pointer/parser offset pair arrays. Do so in a manner that will allow
635         /// future work which will invalidate the cache (by setting it to null)
636         /// </summary>
637         /// <param name="ldftnReverseLookupStatic">pointer to static which holds cache value. This is treated as a volatile variable</param>
638         /// <param name="lookupComputer"></param>
639         /// <returns></returns>
640         private KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>[] GetLdFtnReverseLookups_Helper(ref KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>[] ldftnReverseLookupStatic, Func<NativeFormatModuleInfo, FunctionPointersToOffsets> lookupComputer)
641         {
642             KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>[] ldFtnReverseLookup = Volatile.Read(ref ldftnReverseLookupStatic);
643
644             if (ldFtnReverseLookup != null)
645                 return ldFtnReverseLookup;
646             else
647             {
648                 lock (this)
649                 {
650                     ldFtnReverseLookup = Volatile.Read(ref ldftnReverseLookupStatic);
651
652                     // double checked lock, safe due to use of volatile on s_ldftnReverseHashes
653                     if (ldFtnReverseLookup != null)
654                         return ldFtnReverseLookup;
655
656                     // FUTURE: add a module load callback to invalidate this cache if a new module is loaded.
657                     while (true)
658                     {
659                         int size = 0;
660                         foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
661                         {
662                             size++;
663                         }
664
665                         ldFtnReverseLookup = new KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>[size];
666                         int index = 0;
667                         bool restart = false;
668                         foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
669                         {
670                             // If the module list changes during execution of this code, rebuild from scratch
671                             if (index >= ldFtnReverseLookup.Length)
672                             {
673                                 restart = true;
674                                 break;
675                             }
676
677                             ldFtnReverseLookup[index] = new KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>(module, lookupComputer(module));
678                             index++;
679                         }
680
681                         if (restart)
682                             continue;
683
684                         // unless we need to repeat the module enumeration, only execute the body of this while loop once.
685                         break;
686                     }
687
688                     Volatile.Write(ref ldftnReverseLookupStatic, ldFtnReverseLookup);
689                     return ldFtnReverseLookup;
690                 }
691             }
692         }
693
694         private KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>[] GetLdFtnReverseLookups_InvokeMap()
695         {
696 #pragma warning disable 0420 // GetLdFtnReverseLookups_Helper treats its first parameter as volatile by using explicit Volatile operations
697             return GetLdFtnReverseLookups_Helper(ref _ldftnReverseLookup_InvokeMap, _computeLdFtnLookupInvokeMapInvokeMap);
698 #pragma warning restore 0420
699         }
700
701         internal unsafe void GetFunctionPointerAndInstantiationArgumentForOriginalLdFtnResult(IntPtr originalLdFtnResult, out IntPtr canonOriginalLdFtnResult, out IntPtr instantiationArgument)
702         {
703             if (FunctionPointerOps.IsGenericMethodPointer(originalLdFtnResult))
704             {
705                 GenericMethodDescriptor* realTargetData = FunctionPointerOps.ConvertToGenericDescriptor(originalLdFtnResult);
706                 canonOriginalLdFtnResult = RuntimeAugments.GetCodeTarget(realTargetData->MethodFunctionPointer);
707                 instantiationArgument = realTargetData->InstantiationArgument;
708             }
709             else
710             {
711                 canonOriginalLdFtnResult = RuntimeAugments.GetCodeTarget(originalLdFtnResult);
712                 instantiationArgument = IntPtr.Zero;
713             }
714         }
715
716         internal bool TryGetMethodForOriginalLdFtnResult(IntPtr originalLdFtnResult, ref RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
717         {
718             GetFunctionPointerAndInstantiationArgumentForOriginalLdFtnResult(originalLdFtnResult, out IntPtr canonOriginalLdFtnResult, out IntPtr instantiationArgument);
719
720             if (instantiationArgument != IntPtr.Zero)
721             {
722                 // Search TemplateMethodMap
723                 if (TryGetMethodForOriginalLdFtnResult_GenericMethodWithInstantiationArgument(instantiationArgument, ref declaringTypeHandle, out methodHandle, out genericMethodTypeArgumentHandles))
724                     return true;
725             }
726
727             // Search InvokeMap
728             foreach (KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets> perModuleLookup in GetLdFtnReverseLookups_InvokeMap())
729             {
730                 int startIndex;
731                 int endIndex;
732
733                 if (perModuleLookup.Value.TryGetOffsetsRange(canonOriginalLdFtnResult, out startIndex, out endIndex))
734                 {
735                     for (int curIndex = startIndex; curIndex <= endIndex; curIndex++)
736                     {
737                         uint parserOffset = perModuleLookup.Value.Data[curIndex].Offset;
738                         if (TryGetMethodForOriginalLdFtnResult_InvokeMap_Inner(perModuleLookup.Key, forStartAddress: false, canonOriginalLdFtnResult, instantiationArgument, parserOffset, ref declaringTypeHandle, out methodHandle, out genericMethodTypeArgumentHandles))
739                             return true;
740                     }
741                 }
742             }
743
744             methodHandle = default(QMethodDefinition);
745             genericMethodTypeArgumentHandles = null;
746             return false;
747         }
748
749         internal bool TryGetMethodForStartAddress(IntPtr methodStartAddress, ref RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle)
750         {
751             // Search InvokeMap
752             foreach (KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets> perModuleLookup in GetLdFtnReverseLookups_InvokeMap())
753             {
754                 int startIndex;
755                 int endIndex;
756
757                 if (perModuleLookup.Value.TryGetOffsetsRange(methodStartAddress, out startIndex, out endIndex))
758                 {
759                     for (int curIndex = startIndex; curIndex <= endIndex; curIndex++)
760                     {
761                         uint parserOffset = perModuleLookup.Value.Data[curIndex].Offset;
762                         if (TryGetMethodForOriginalLdFtnResult_InvokeMap_Inner(perModuleLookup.Key, forStartAddress: true, methodStartAddress, IntPtr.Zero, parserOffset, ref declaringTypeHandle, out methodHandle, out _))
763                         {
764                             if (RuntimeAugments.IsGenericType(declaringTypeHandle))
765                                 declaringTypeHandle = RuntimeAugments.GetGenericDefinition(declaringTypeHandle);
766                             return true;
767                         }
768                     }
769                 }
770             }
771
772             methodHandle = default(QMethodDefinition);
773             return false;
774         }
775
776         private static FunctionPointersToOffsets ComputeLdftnReverseLookup_InvokeMap(NativeFormatModuleInfo mappingTableModule)
777         {
778             FunctionPointersToOffsets functionPointerToOffsetInInvokeMap = new FunctionPointersToOffsets();
779
780             NativeReader invokeMapReader;
781             if (!TryGetNativeReaderForBlob(mappingTableModule, ReflectionMapBlob.InvokeMap, out invokeMapReader))
782             {
783                 return functionPointerToOffsetInInvokeMap;
784             }
785
786             ExternalReferencesTable externalReferences = default(ExternalReferencesTable);
787             externalReferences.InitializeCommonFixupsTable(mappingTableModule);
788
789             NativeParser invokeMapParser = new NativeParser(invokeMapReader, 0);
790             NativeHashtable invokeHashtable = new NativeHashtable(invokeMapParser);
791
792             LowLevelList<FunctionPointerOffsetPair> functionPointers = new LowLevelList<FunctionPointerOffsetPair>();
793
794             var lookup = invokeHashtable.EnumerateAllEntries();
795             NativeParser entryParser;
796             while (!(entryParser = lookup.GetNext()).IsNull)
797             {
798                 uint parserOffset = entryParser.Offset;
799                 Debug.Assert(entryParser.Reader == invokeMapParser.Reader);
800
801                 InvokeTableFlags entryFlags = (InvokeTableFlags)entryParser.GetUnsigned();
802
803                 bool hasEntrypoint = ((entryFlags & InvokeTableFlags.HasEntrypoint) != 0);
804                 if (!hasEntrypoint)
805                     continue;
806
807                 entryParser.SkipInteger(); // entryMethodHandleOrNameAndSigRaw
808                 entryParser.SkipInteger(); // entryDeclaringTypeRaw
809
810                 IntPtr entryMethodEntrypoint = externalReferences.GetFunctionPointerFromIndex(entryParser.GetUnsigned());
811                 functionPointers.Add(new FunctionPointerOffsetPair(entryMethodEntrypoint, parserOffset));
812
813                 // Add resolved stub targets to the reverse LdFtn lookup map for the purpose of reflection-based
814                 // stack trace resolution - the reverse LdFtn lookup internally used by the reflection
815                 // method resolution will work off an IP address on the stack which is an address
816                 // within the actual method, not the stub.
817                 IntPtr targetAddress = RuntimeAugments.GetCodeTarget(entryMethodEntrypoint);
818                 if (targetAddress != IntPtr.Zero && targetAddress != entryMethodEntrypoint)
819                 {
820                     functionPointers.Add(new FunctionPointerOffsetPair(targetAddress, parserOffset));
821                 }
822                 IntPtr targetAddress2;
823                 if (TypeLoaderEnvironment.TryGetTargetOfUnboxingAndInstantiatingStub(entryMethodEntrypoint, out targetAddress2) &&
824                     targetAddress2 != entryMethodEntrypoint &&
825                     targetAddress2 != targetAddress)
826                 {
827                     functionPointers.Add(new FunctionPointerOffsetPair(targetAddress2, parserOffset));
828                 }
829             }
830
831             functionPointerToOffsetInInvokeMap.Data = functionPointers.ToArray();
832             Array.Sort(functionPointerToOffsetInInvokeMap.Data);
833
834             return functionPointerToOffsetInInvokeMap;
835         }
836
837         private unsafe bool TryGetMethodForOriginalLdFtnResult_InvokeMap_Inner(NativeFormatModuleInfo mappingTableModule, bool forStartAddress, IntPtr canonOriginalLdFtnResult, IntPtr instantiationArgument, uint parserOffset, ref RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
838         {
839             methodHandle = default(QMethodDefinition);
840             genericMethodTypeArgumentHandles = null;
841
842             NativeReader invokeMapReader;
843             if (!TryGetNativeReaderForBlob(mappingTableModule, ReflectionMapBlob.InvokeMap, out invokeMapReader))
844             {
845                 // This should have succeeded otherwise, how did we get a parser offset as an input parameter?
846                 Debug.Assert(false);
847                 return false;
848             }
849
850             ExternalReferencesTable externalReferences = default(ExternalReferencesTable);
851             externalReferences.InitializeCommonFixupsTable(mappingTableModule);
852
853             NativeParser entryParser = new NativeParser(invokeMapReader, parserOffset);
854
855             InvokeTableFlags entryFlags = (InvokeTableFlags)entryParser.GetUnsigned();
856
857             // If the passed in method was a fat function pointer, but the entry in the mapping table doesn't need
858             // an instantiation argument (or the other way around), trivially reject it.
859             if (!forStartAddress && ((instantiationArgument == IntPtr.Zero) != ((entryFlags & InvokeTableFlags.RequiresInstArg) == 0)))
860                 return false;
861
862             Debug.Assert((entryFlags & InvokeTableFlags.HasEntrypoint) != 0);
863
864             uint entryMethodHandleOrNameAndSigRaw = entryParser.GetUnsigned();
865             uint entryDeclaringTypeRaw = entryParser.GetUnsigned();
866
867             IntPtr entryMethodEntrypoint = externalReferences.GetFunctionPointerFromIndex(entryParser.GetUnsigned());
868
869             if ((entryFlags & InvokeTableFlags.NeedsParameterInterpretation) == 0)
870                 entryParser.SkipInteger(); // skip dynamic invoke cookie
871
872             if (forStartAddress)
873             {
874                 declaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryDeclaringTypeRaw);
875             }
876             else
877             {
878 #if DEBUG
879                 IntPtr targetAddress;
880                 Debug.Assert(entryMethodEntrypoint == canonOriginalLdFtnResult ||
881                     RuntimeAugments.GetCodeTarget(entryMethodEntrypoint) == canonOriginalLdFtnResult ||
882                     TypeLoaderEnvironment.TryGetTargetOfUnboxingAndInstantiatingStub(entryMethodEntrypoint, out targetAddress) &&
883                         targetAddress == canonOriginalLdFtnResult);
884 #endif
885
886                 if ((entryFlags & InvokeTableFlags.RequiresInstArg) == 0 && declaringTypeHandle.IsNull())
887                     declaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryDeclaringTypeRaw);
888
889                 if ((entryFlags & InvokeTableFlags.IsGenericMethod) != 0)
890                 {
891                     if ((entryFlags & InvokeTableFlags.RequiresInstArg) != 0)
892                     {
893                         MethodNameAndSignature dummyNameAndSignature;
894                         bool success = TypeLoaderEnvironment.Instance.TryGetGenericMethodComponents(instantiationArgument, out declaringTypeHandle, out dummyNameAndSignature, out genericMethodTypeArgumentHandles);
895                         Debug.Assert(success);
896                     }
897                     else
898                         genericMethodTypeArgumentHandles = GetTypeSequence(ref externalReferences, ref entryParser);
899                 }
900                 else
901                 {
902                     genericMethodTypeArgumentHandles = null;
903                     if ((entryFlags & InvokeTableFlags.RequiresInstArg) != 0)
904                         declaringTypeHandle = RuntimeAugments.CreateRuntimeTypeHandle(instantiationArgument);
905                 }
906
907                 RuntimeTypeHandle entryType = externalReferences.GetRuntimeTypeHandleFromIndex(entryDeclaringTypeRaw);
908                 declaringTypeHandle = GetExactDeclaringType(entryType, declaringTypeHandle);
909             }
910
911             if ((entryFlags & InvokeTableFlags.HasMetadataHandle) != 0)
912             {
913                 RuntimeTypeHandle declaringTypeHandleDefinition = GetTypeDefinition(declaringTypeHandle);
914                 QTypeDefinition qTypeDefinition;
915                 if (!TryGetMetadataForNamedType(declaringTypeHandleDefinition, out qTypeDefinition))
916                 {
917                     RuntimeExceptionHelpers.FailFast("Unable to resolve named type to having a metadata reader");
918                 }
919
920                 MethodHandle nativeFormatMethodHandle =
921                     (((int)HandleType.Method << 24) | (int)entryMethodHandleOrNameAndSigRaw).AsMethodHandle();
922
923                 methodHandle = new QMethodDefinition(qTypeDefinition.NativeFormatReader, nativeFormatMethodHandle);
924             }
925             else
926             {
927                 uint nameAndSigOffset = entryMethodHandleOrNameAndSigRaw;
928                 MethodNameAndSignature nameAndSig;
929                 if (!TypeLoaderEnvironment.Instance.TryGetMethodNameAndSignatureFromNativeLayoutOffset(mappingTableModule.Handle, nameAndSigOffset, out nameAndSig))
930                 {
931                     Debug.Assert(false);
932                     return false;
933                 }
934
935                 if (!TypeLoaderEnvironment.Instance.TryGetMetadataForTypeMethodNameAndSignature(declaringTypeHandle, nameAndSig, out methodHandle))
936                 {
937                     Debug.Assert(false);
938                     return false;
939                 }
940             }
941
942             return true;
943         }
944
945         private static unsafe bool TryGetMethodForOriginalLdFtnResult_GenericMethodWithInstantiationArgument(IntPtr instantiationArgument, ref RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
946         {
947             MethodNameAndSignature nameAndSig;
948             bool success = TypeLoaderEnvironment.Instance.TryGetGenericMethodComponents(instantiationArgument, out declaringTypeHandle, out nameAndSig, out genericMethodTypeArgumentHandles);
949             if (success)
950             {
951                 if (TypeLoaderEnvironment.Instance.TryGetMetadataForTypeMethodNameAndSignature(declaringTypeHandle, nameAndSig, out methodHandle))
952                 {
953                     return true;
954                 }
955             }
956
957             methodHandle = default(QMethodDefinition);
958
959             return false;
960         }
961
962         public sealed override FieldAccessor TryGetFieldAccessor(
963             MetadataReader metadataReader,
964             RuntimeTypeHandle declaringTypeHandle,
965             RuntimeTypeHandle fieldTypeHandle,
966             FieldHandle fieldHandle)
967         {
968             FieldAccessMetadata fieldAccessMetadata;
969
970             if (!TypeLoaderEnvironment.TryGetFieldAccessMetadata(
971                 metadataReader,
972                 declaringTypeHandle,
973                 fieldHandle,
974                 out fieldAccessMetadata))
975             {
976                 return null;
977             }
978
979             FieldTableFlags fieldBase = fieldAccessMetadata.Flags & FieldTableFlags.StorageClass;
980             switch (fieldBase)
981             {
982                 case FieldTableFlags.Instance:
983                     {
984                         int fieldOffsetDelta = RuntimeAugments.IsValueType(declaringTypeHandle) ? IntPtr.Size : 0;
985
986                         return RuntimeAugments.IsValueType(fieldTypeHandle) ?
987                             (FieldAccessor)new ValueTypeFieldAccessorForInstanceFields(
988                                 fieldAccessMetadata.Offset + fieldOffsetDelta, declaringTypeHandle, fieldTypeHandle) :
989                             RuntimeAugments.IsUnmanagedPointerType(fieldTypeHandle) ?
990                                 (FieldAccessor)new PointerTypeFieldAccessorForInstanceFields(
991                                     fieldAccessMetadata.Offset + fieldOffsetDelta, declaringTypeHandle, fieldTypeHandle) :
992                                 (FieldAccessor)new ReferenceTypeFieldAccessorForInstanceFields(
993                                     fieldAccessMetadata.Offset + fieldOffsetDelta, declaringTypeHandle, fieldTypeHandle);
994                     }
995
996                 case FieldTableFlags.NonGCStatic:
997                 case FieldTableFlags.GCStatic:
998                 case FieldTableFlags.ThreadStatic:
999                     {
1000                         int fieldOffset;
1001                         IntPtr staticsBase;
1002
1003                         if (RuntimeAugments.IsGenericType(declaringTypeHandle))
1004                         {
1005                             unsafe
1006                             {
1007                                 fieldOffset = fieldAccessMetadata.Offset;
1008                                 staticsBase = fieldBase switch
1009                                 {
1010                                     FieldTableFlags.GCStatic => TypeLoaderEnvironment.Instance.TryGetGcStaticFieldData(declaringTypeHandle),
1011                                     FieldTableFlags.NonGCStatic => TypeLoaderEnvironment.Instance.TryGetNonGcStaticFieldData(declaringTypeHandle),
1012                                     _ => TypeLoaderEnvironment.Instance.TryGetThreadStaticFieldData(declaringTypeHandle),
1013                                 };
1014                             }
1015                         }
1016                         else
1017                         {
1018                             Debug.Assert((fieldAccessMetadata.Flags & FieldTableFlags.IsUniversalCanonicalEntry) == 0);
1019
1020                             if (fieldBase != FieldTableFlags.NonGCStatic)
1021                             {
1022                                 fieldOffset = fieldAccessMetadata.Offset;
1023                                 staticsBase = fieldAccessMetadata.Cookie;
1024                             }
1025                             else
1026                             {
1027                                 // The fieldAccessMetadata.Cookie value points directly to the field's data. We'll use that as the 'staticsBase'
1028                                 // and just use a field offset of zero.
1029                                 fieldOffset = 0;
1030                                 staticsBase = fieldAccessMetadata.Cookie;
1031                             }
1032                         }
1033
1034                         IntPtr cctorContext = TryGetStaticClassConstructionContext(declaringTypeHandle);
1035
1036                         return RuntimeAugments.IsValueType(fieldTypeHandle) ?
1037                             (FieldAccessor)new ValueTypeFieldAccessorForStaticFields(cctorContext, staticsBase, fieldOffset, fieldAccessMetadata.Flags, fieldTypeHandle) :
1038                             RuntimeAugments.IsUnmanagedPointerType(fieldTypeHandle) ?
1039                                 (FieldAccessor)new PointerTypeFieldAccessorForStaticFields(cctorContext, staticsBase, fieldOffset, fieldAccessMetadata.Flags, fieldTypeHandle) :
1040                                 (FieldAccessor)new ReferenceTypeFieldAccessorForStaticFields(cctorContext, staticsBase, fieldOffset, fieldAccessMetadata.Flags, fieldTypeHandle);
1041                     }
1042             }
1043
1044             return null;
1045         }
1046
1047         //
1048         // This resolves RuntimeMethodHandles for methods declared on non-generic types (declaringTypeHandle is an output of this method.)
1049         //
1050         public sealed override unsafe bool TryGetMethodFromHandle(RuntimeMethodHandle runtimeMethodHandle, out RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
1051         {
1052             MethodNameAndSignature nameAndSignature;
1053             methodHandle = default(QMethodDefinition);
1054             if (!TypeLoaderEnvironment.Instance.TryGetRuntimeMethodHandleComponents(runtimeMethodHandle, out declaringTypeHandle, out nameAndSignature, out genericMethodTypeArgumentHandles))
1055                 return false;
1056
1057             return TypeLoaderEnvironment.Instance.TryGetMetadataForTypeMethodNameAndSignature(declaringTypeHandle, nameAndSignature, out methodHandle);
1058         }
1059
1060         //
1061         // This resolves RuntimeMethodHandles for methods declared on generic types (declaringTypeHandle is an input of this method.)
1062         //
1063         public sealed override bool TryGetMethodFromHandleAndType(RuntimeMethodHandle runtimeMethodHandle, RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
1064         {
1065             return TryGetMethodFromHandle(runtimeMethodHandle, out _, out methodHandle, out genericMethodTypeArgumentHandles);
1066         }
1067
1068         //
1069         // This resolves RuntimeFieldHandles for fields declared on non-generic types (declaringTypeHandle is an output of this method.)
1070         //
1071         public sealed override unsafe bool TryGetFieldFromHandle(RuntimeFieldHandle runtimeFieldHandle, out RuntimeTypeHandle declaringTypeHandle, out FieldHandle fieldHandle)
1072         {
1073             fieldHandle = default(FieldHandle);
1074
1075             string fieldName;
1076             if (!TypeLoaderEnvironment.Instance.TryGetRuntimeFieldHandleComponents(runtimeFieldHandle, out declaringTypeHandle, out fieldName))
1077                 return false;
1078
1079             QTypeDefinition qTypeDefinition;
1080             RuntimeTypeHandle metadataLookupTypeHandle = GetTypeDefinition(declaringTypeHandle);
1081
1082             if (!TryGetMetadataForNamedType(metadataLookupTypeHandle, out qTypeDefinition))
1083                 return false;
1084
1085             // TODO! Handle ecma style types
1086             MetadataReader reader = qTypeDefinition.NativeFormatReader;
1087             TypeDefinitionHandle typeDefinitionHandle = qTypeDefinition.NativeFormatHandle;
1088
1089             TypeDefinition typeDefinition = typeDefinitionHandle.GetTypeDefinition(reader);
1090             foreach (FieldHandle fh in typeDefinition.Fields)
1091             {
1092                 Field field = fh.GetField(reader);
1093                 if (field.Name.StringEquals(fieldName, reader))
1094                 {
1095                     fieldHandle = fh;
1096                     return true;
1097                 }
1098             }
1099
1100             return false;
1101         }
1102
1103         //
1104         // This resolves RuntimeFieldHandles for fields declared on generic types (declaringTypeHandle is an input of this method.)
1105         //
1106         public sealed override bool TryGetFieldFromHandleAndType(RuntimeFieldHandle runtimeFieldHandle, RuntimeTypeHandle declaringTypeHandle, out FieldHandle fieldHandle)
1107         {
1108             return TryGetFieldFromHandle(runtimeFieldHandle, out _, out fieldHandle);
1109         }
1110
1111         /// <summary>
1112         /// Locate the static constructor context given the runtime type handle (MethodTable) for the type in question.
1113         /// </summary>
1114         /// <param name="typeHandle">MethodTable of the type to look up</param>
1115         internal static unsafe IntPtr TryGetStaticClassConstructionContext(RuntimeTypeHandle typeHandle)
1116         {
1117             return TypeLoaderEnvironment.TryGetStaticClassConstructionContext(typeHandle);
1118         }
1119
1120         private struct MethodParametersInfo
1121         {
1122             private MetadataReader _metadataReader;
1123             private MethodBase _methodBase;
1124             private MethodHandle _methodHandle;
1125
1126             private Handle[] _returnTypeAndParametersHandlesCache;
1127             private Type[] _returnTypeAndParametersTypesCache;
1128
1129             public MethodParametersInfo(MethodBase methodBase)
1130             {
1131                 _metadataReader = null;
1132                 _methodBase = methodBase;
1133                 _methodHandle = default(MethodHandle);
1134                 _returnTypeAndParametersHandlesCache = null;
1135                 _returnTypeAndParametersTypesCache = null;
1136             }
1137
1138             public MethodParametersInfo(MetadataReader metadataReader, MethodBase methodBase, MethodHandle methodHandle)
1139             {
1140                 _metadataReader = metadataReader;
1141                 _methodBase = methodBase;
1142                 _methodHandle = methodHandle;
1143                 _returnTypeAndParametersHandlesCache = null;
1144                 _returnTypeAndParametersTypesCache = null;
1145             }
1146
1147             public LowLevelList<RuntimeTypeHandle> ParameterTypeHandles
1148             {
1149                 get
1150                 {
1151                     ParameterInfo[] parameters = _methodBase.GetParametersNoCopy();
1152                     LowLevelList<RuntimeTypeHandle> result = new LowLevelList<RuntimeTypeHandle>(parameters.Length);
1153
1154                     for (int i = 0; i < parameters.Length; i++)
1155                     {
1156                         Type parameterType = parameters[i].ParameterType;
1157
1158                         if (parameterType.IsByRef)
1159                             result.Add(parameterType.GetElementType().TypeHandle);
1160                         else if (parameterType.IsEnum && !parameters[i].HasDefaultValue)
1161                             result.Add(Enum.GetUnderlyingType(parameterType).TypeHandle);
1162                         else
1163                             result.Add(parameterType.TypeHandle);
1164                     }
1165
1166                     return result;
1167                 }
1168             }
1169
1170             public RuntimeTypeHandle ReturnTypeHandle
1171             {
1172                 get
1173                 {
1174                     MethodInfo reflectionMethodInfo = _methodBase as MethodInfo;
1175                     Type returnType = reflectionMethodInfo != null ? reflectionMethodInfo.ReturnType : typeof(void);
1176                     if (returnType.IsByRef)
1177                         returnType = returnType.GetElementType();
1178                     return returnType.TypeHandle;
1179                 }
1180             }
1181
1182             public LowLevelList<RuntimeTypeHandle> ReturnTypeAndParameterTypeHandles
1183             {
1184                 get
1185                 {
1186                     LowLevelList<RuntimeTypeHandle> result = ParameterTypeHandles;
1187                     result.Insert(0, ReturnTypeHandle);
1188                     return result;
1189                 }
1190             }
1191
1192             public bool[] ReturnTypeAndParametersByRefFlags
1193             {
1194                 get
1195                 {
1196                     ParameterInfo[] parameters = _methodBase.GetParametersNoCopy();
1197                     bool[] result = new bool[parameters.Length + 1];
1198
1199                     MethodInfo reflectionMethodInfo = _methodBase as MethodInfo;
1200                     Type returnType = reflectionMethodInfo != null ? reflectionMethodInfo.ReturnType : typeof(void);
1201                     result[0] = returnType.IsByRef;
1202
1203                     for (int i = 0; i < parameters.Length; i++)
1204                         result[i + 1] = parameters[i].ParameterType.IsByRef;
1205
1206                     return result;
1207                 }
1208             }
1209
1210             private void GetReturnTypeAndParameterTypesAndMDHandles(ref Handle[] handles, ref Type[] types)
1211             {
1212                 if (_returnTypeAndParametersTypesCache == null)
1213                 {
1214                     Debug.Assert(_metadataReader != null && !_methodHandle.Equals(default(MethodHandle)));
1215
1216                     _returnTypeAndParametersHandlesCache = new Handle[_methodBase.GetParametersNoCopy().Length + 1];
1217                     _returnTypeAndParametersTypesCache = new Type[_methodBase.GetParametersNoCopy().Length + 1];
1218
1219                     MethodSignature signature = _methodHandle.GetMethod(_metadataReader).Signature.GetMethodSignature(_metadataReader);
1220
1221                     // Check the return type for generic vars
1222                     MethodInfo reflectionMethodInfo = _methodBase as MethodInfo;
1223                     _returnTypeAndParametersTypesCache[0] = reflectionMethodInfo != null ? reflectionMethodInfo.ReturnType : typeof(void);
1224                     _returnTypeAndParametersHandlesCache[0] = signature.ReturnType;
1225
1226                     // Check the method parameters for generic vars
1227                     int index = 1;
1228                     foreach (Handle paramSigHandle in signature.Parameters)
1229                     {
1230                         _returnTypeAndParametersHandlesCache[index] = paramSigHandle;
1231                         _returnTypeAndParametersTypesCache[index] = _methodBase.GetParametersNoCopy()[index - 1].ParameterType;
1232                         index++;
1233                     }
1234                 }
1235
1236                 handles = _returnTypeAndParametersHandlesCache;
1237                 types = _returnTypeAndParametersTypesCache;
1238                 Debug.Assert(handles != null && types != null);
1239             }
1240         }
1241     }
1242 }