1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
5 using global::System.Reflection;
6 using global::System.Collections.Generic;
8 using global::Internal.Runtime.Augments;
9 using global::Internal.Runtime.CompilerServices;
10 using global::Internal.Runtime.TypeLoader;
12 using global::Internal.Reflection.Core.Execution;
13 using global::Internal.Reflection.Execution.MethodInvokers;
14 using global::Internal.Reflection.Execution.FieldAccessors;
16 using global::Internal.Metadata.NativeFormat;
18 using global::System.Runtime.InteropServices;
20 using global::Internal.Runtime;
21 using global::Internal.NativeFormat;
23 using System.Reflection.Runtime.General;
24 using System.Threading;
26 using CanonicalFormKind = global::Internal.TypeSystem.CanonicalFormKind;
29 using Debug = System.Diagnostics.Debug;
31 namespace Internal.Reflection.Execution
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.
37 // - Except when otherwise noted, ExecutionEnvironment methods use the "TryGet*" pattern rather than throwing exceptions.
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.
41 //==========================================================================================================
42 internal sealed partial class ExecutionEnvironmentImplementation : ExecutionEnvironment
44 private static RuntimeTypeHandle GetOpenTypeDefinition(RuntimeTypeHandle typeHandle, out RuntimeTypeHandle[] typeArgumentsHandles)
46 if (RuntimeAugments.IsGenericType(typeHandle))
48 return RuntimeAugments.GetGenericInstantiation(typeHandle, out typeArgumentsHandles);
51 typeArgumentsHandles = null;
55 private static RuntimeTypeHandle GetTypeDefinition(RuntimeTypeHandle typeHandle)
57 if (RuntimeAugments.IsGenericType(typeHandle))
58 return RuntimeAugments.GetGenericDefinition(typeHandle);
63 private static bool RuntimeTypeHandleIsNonDefault(RuntimeTypeHandle runtimeTypeHandle)
65 return ((IntPtr)RuntimeAugments.GetPointerFromTypeHandle(runtimeTypeHandle)) != IntPtr.Zero;
68 private static unsafe NativeReader GetNativeReaderForBlob(NativeFormatModuleInfo module, ReflectionMapBlob blob)
71 if (TryGetNativeReaderForBlob(module, blob, out reader))
77 return default(NativeReader);
80 private static unsafe bool TryGetNativeReaderForBlob(NativeFormatModuleInfo module, ReflectionMapBlob blob, out NativeReader reader)
85 if (module.TryFindBlob((int)blob, out pBlob, out cbBlob))
87 reader = new NativeReader(pBlob, cbBlob);
91 reader = default(NativeReader);
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).
100 /// runtimeTypeHandle is a typedef (not a constructed type such as an array or generic instance.)
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)
106 Debug.Assert(!RuntimeAugments.IsGenericType(runtimeTypeHandle));
107 return TypeLoaderEnvironment.Instance.TryGetMetadataForNamedType(runtimeTypeHandle, out qTypeDefinition);
111 // Return true for a TypeDef if the policy has decided this type is blocked from reflection.
114 // runtimeTypeHandle is a typedef or a generic type instance (not a constructed type such as an array)
116 public sealed override unsafe bool IsReflectionBlocked(RuntimeTypeHandle runtimeTypeHandle)
118 // For generic types, use the generic type definition
119 runtimeTypeHandle = GetTypeDefinition(runtimeTypeHandle);
120 var moduleHandle = RuntimeAugments.GetModuleFromTypeHandle(runtimeTypeHandle);
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)))
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);
135 int hashcode = runtimeTypeHandle.GetHashCode();
136 var lookup = blockedReflectionHashtable.Lookup(hashcode);
137 NativeParser entryParser;
138 while (!(entryParser = lookup.GetNext()).IsNull)
140 RuntimeTypeHandle entryType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
141 if (!entryType.Equals(runtimeTypeHandle))
144 // Entry found, must be blocked
147 // Entry not found, must not be blocked
152 /// Return the RuntimeTypeHandle for the named type described in metadata. This is used to implement the Create and Invoke
156 /// metadataReader + typeDefHandle - a valid metadata reader + typeDefinitionHandle where "metadataReader" is one
157 /// of the metadata readers returned by ExecutionEnvironment.MetadataReaders.
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.
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)
166 return TypeLoaderEnvironment.Instance.TryGetNamedTypeForMetadata(qTypeDefinition, out runtimeTypeHandle);
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.)
173 /// This is only used in "debug" builds to provide better missing metadata diagnostics.
176 /// runtimeTypeHandle is a typedef (not a constructed type such as an array or generic instance.)
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)
183 return TypeLoaderEnvironment.TryGetTypeReferenceForNamedType(runtimeTypeHandle, out metadataReader, out typeRefHandle);
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.)
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().
195 /// metadataReader + typeRefHandle - a valid metadata reader + typeReferenceHandle where "metadataReader" is one
196 /// of the metadata readers returned by ExecutionEnvironment.MetadataReaders.
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.
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)
206 return TypeLoaderEnvironment.TryGetNamedTypeForTypeReference(metadataReader, typeRefHandle, out runtimeTypeHandle);
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().
214 // elementTypeHandle is a valid RuntimeTypeHandle.
216 // This is not equivalent to calling TryGetMultiDimTypeForElementType() with a rank of 1!
218 public sealed override unsafe bool TryGetArrayTypeForElementType(RuntimeTypeHandle elementTypeHandle, out RuntimeTypeHandle arrayTypeHandle)
220 if (RuntimeAugments.IsGenericTypeDefinition(elementTypeHandle))
222 arrayTypeHandle = default(RuntimeTypeHandle);
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);
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.
235 // arrayTypeHandle is a valid RuntimeTypeHandle of type array.
237 // This is not equivalent to calling TryGetMultiDimTypeElementType() with a rank of 1!
239 public sealed override unsafe bool TryGetArrayTypeElementType(RuntimeTypeHandle arrayTypeHandle, out RuntimeTypeHandle elementTypeHandle)
241 elementTypeHandle = RuntimeAugments.GetRelatedParameterTypeHandle(arrayTypeHandle);
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).
251 // elementTypeHandle is a valid RuntimeTypeHandle.
253 // Calling this with rank 1 is not equivalent to calling TryGetArrayTypeForElementType()!
255 public sealed override unsafe bool TryGetMultiDimArrayTypeForElementType(RuntimeTypeHandle elementTypeHandle, int rank, out RuntimeTypeHandle arrayTypeHandle)
257 if (RuntimeAugments.IsGenericTypeDefinition(elementTypeHandle))
259 arrayTypeHandle = default(RuntimeTypeHandle);
263 if ((rank < MDArray.MinRank) || (rank > MDArray.MaxRank))
265 throw new TypeLoadException(SR.Format(SR.MultiDim_Of_This_Rank_Not_Supported, rank));
268 return TypeLoaderEnvironment.Instance.TryGetArrayTypeForElementType(elementTypeHandle, true, rank, out arrayTypeHandle);
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.
276 // targetTypeHandle is a valid RuntimeTypeHandle.
278 public sealed override unsafe bool TryGetPointerTypeForTargetType(RuntimeTypeHandle targetTypeHandle, out RuntimeTypeHandle pointerTypeHandle)
280 return TypeLoaderEnvironment.Instance.TryGetPointerTypeForTargetType(targetTypeHandle, out pointerTypeHandle);
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.
288 // pointerTypeHandle is a valid RuntimeTypeHandle of type pointer.
290 public sealed override unsafe bool TryGetPointerTypeTargetType(RuntimeTypeHandle pointerTypeHandle, out RuntimeTypeHandle targetTypeHandle)
292 targetTypeHandle = RuntimeAugments.GetRelatedParameterTypeHandle(pointerTypeHandle);
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.
301 // targetTypeHandle is a valid RuntimeTypeHandle.
303 public sealed override unsafe bool TryGetByRefTypeForTargetType(RuntimeTypeHandle targetTypeHandle, out RuntimeTypeHandle byRefTypeHandle)
305 return TypeLoaderEnvironment.Instance.TryGetByRefTypeForTargetType(targetTypeHandle, out byRefTypeHandle);
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.
313 // byRefTypeHandle is a valid RuntimeTypeHandle of a byref.
315 public sealed override unsafe bool TryGetByRefTypeTargetType(RuntimeTypeHandle byRefTypeHandle, out RuntimeTypeHandle targetTypeHandle)
317 targetTypeHandle = RuntimeAugments.GetRelatedParameterTypeHandle(byRefTypeHandle);
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().
326 // runtimeTypeDefinitionHandle is a valid RuntimeTypeHandle for a generic type.
327 // genericTypeArgumentHandles is an array of valid RuntimeTypeHandles.
329 public sealed override unsafe bool TryGetConstructedGenericTypeForComponents(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle)
331 if (TypeLoaderEnvironment.Instance.TryLookupConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out runtimeTypeHandle))
336 Type typeDefinition = Type.GetTypeFromHandle(genericTypeDefinitionHandle);
338 Type[] typeArguments = new Type[genericTypeArgumentHandles.Length];
339 for (int i = 0; i < genericTypeArgumentHandles.Length; i++)
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
345 if (RuntimeAugments.IsGenericTypeDefinition(genericTypeArgumentHandles[i]))
348 typeArguments[i] = Type.GetTypeFromHandle(genericTypeArgumentHandles[i]);
351 ConstraintValidator.EnsureSatisfiesClassConstraints(typeDefinition, typeArguments);
353 return TypeLoaderEnvironment.Instance.TryGetConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out runtimeTypeHandle);
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().
361 // runtimeTypeDefinitionHandle is a valid RuntimeTypeHandle for a generic type.
362 // genericTypeArgumentHandles is an array of valid RuntimeTypeHandles.
364 public sealed override unsafe bool TryGetConstructedGenericTypeForComponentsNoConstraintCheck(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle)
366 return TypeLoaderEnvironment.Instance.TryGetConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out runtimeTypeHandle);
369 public sealed override MethodInvoker TryGetMethodInvoker(RuntimeTypeHandle declaringTypeHandle, QMethodDefinition methodHandle, RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
371 MethodBase methodInfo = ReflectionCoreExecution.ExecutionDomain.GetMethod(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles);
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);
378 MethodSignatureComparer methodSignatureComparer = new MethodSignatureComparer(methodHandle);
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.
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);
391 methodInvokeInfo = TryGetMethodInvokeInfo(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles,
392 methodInfo, ref methodSignatureComparer, CanonicalFormKind.Universal);
394 methodInvokeInfo = TryGetMethodInvokeInfo(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles,
395 methodInfo, ref methodSignatureComparer, CanonicalFormKind.Specific);
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);
403 if (methodInvokeInfo == null)
406 return MethodInvokerWithMethodInvokeInfo.CreateMethodInvoker(declaringTypeHandle, methodHandle, methodInvokeInfo);
410 // Get the pointer of a dynamic method invocation thunk
412 private static IntPtr GetDynamicMethodInvoke(NativeFormatModuleInfo module, uint cookie)
414 ExternalReferencesTable extRefs = default(ExternalReferencesTable);
415 extRefs.InitializeCommonFixupsTable(module);
417 return extRefs.GetFunctionPointerFromIndex(cookie);
420 private static RuntimeTypeHandle[] GetTypeSequence(ref ExternalReferencesTable extRefs, ref NativeParser parser)
422 uint count = parser.GetUnsigned();
423 RuntimeTypeHandle[] result = new RuntimeTypeHandle[count];
424 for (uint i = 0; i < count; i++)
426 result[i] = extRefs.GetRuntimeTypeHandleFromIndex(parser.GetUnsigned());
431 private static IntPtr TryGetVirtualResolveData(NativeFormatModuleInfo module,
432 RuntimeTypeHandle methodHandleDeclaringType, QMethodDefinition methodHandle, RuntimeTypeHandle[] genericArgs,
433 ref MethodSignatureComparer methodSignatureComparer)
435 TypeLoaderEnvironment.VirtualResolveDataResult lookupResult;
436 bool success = TypeLoaderEnvironment.TryGetVirtualResolveData(module, methodHandleDeclaringType, genericArgs, ref methodSignatureComparer, out lookupResult);
441 GCHandle reader = Internal.TypeSystem.LockFreeObjectInterner.GetInternedObjectHandle(methodHandle.Reader);
443 if (lookupResult.IsGVM)
445 return (new OpenMethodResolver(lookupResult.DeclaringInvokeType, lookupResult.GVMHandle, reader, methodHandle.Token)).ToIntPtr();
449 return (new OpenMethodResolver(lookupResult.DeclaringInvokeType, lookupResult.SlotIndex, reader, methodHandle.Token)).ToIntPtr();
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.
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)
473 MethodInvokeMetadata methodInvokeMetadata;
475 if (!TypeLoaderEnvironment.TryGetMethodInvokeMetadata(
478 genericMethodTypeArgumentHandles,
479 ref methodSignatureComparer,
481 out methodInvokeMetadata))
483 // Method invoke info not found
487 if ((methodInvokeMetadata.InvokeTableFlags & InvokeTableFlags.CallingConventionMask) != 0)
489 // MethodInvokeInfo found, but it references a method with a native calling convention.
493 IntPtr dynamicInvokeMethod;
494 Debug.Assert((methodInvokeMetadata.InvokeTableFlags & InvokeTableFlags.NeedsParameterInterpretation) == 0);
495 dynamicInvokeMethod = GetDynamicMethodInvoke(
496 methodInvokeMetadata.MappingTableModule,
497 methodInvokeMetadata.DynamicInvokeCookie);
499 IntPtr resolver = IntPtr.Zero;
500 if ((methodInvokeMetadata.InvokeTableFlags & InvokeTableFlags.HasVirtualInvoke) != 0)
502 resolver = TryGetVirtualResolveData(ModuleList.Instance.GetModuleInfoForMetadataReader(methodHandle.NativeFormatReader),
503 declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles,
504 ref methodSignatureComparer);
506 // Unable to find virtual resolution information, cannot return valid MethodInvokeInfo
507 if (resolver == IntPtr.Zero)
511 var methodInvokeInfo = new MethodInvokeInfo(methodInfo, dynamicInvokeMethod)
513 LdFtnResult = methodInvokeMetadata.MethodEntryPoint,
514 VirtualResolveData = resolver,
516 return methodInvokeInfo;
519 private static RuntimeTypeHandle GetExactDeclaringType(RuntimeTypeHandle dstType, RuntimeTypeHandle srcType)
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.
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>.
532 // This method needs to return "true" and "Base<string>" for cases like this.
534 RuntimeTypeHandle dstTypeDef = GetTypeDefinition(dstType);
536 while (!srcType.IsNull())
538 if (RuntimeAugments.IsAssignableFrom(dstType, srcType))
543 if (!dstTypeDef.IsNull() && RuntimeAugments.IsGenericType(srcType))
545 RuntimeTypeHandle srcTypeDef = GetTypeDefinition(srcType);;
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))
551 // Return the *other* type handle since dstType is instantiated over different arguments
556 if (!RuntimeAugments.TryGetBaseType(srcType, out srcType))
563 return default(RuntimeTypeHandle);
566 private struct FunctionPointerOffsetPair : IComparable<FunctionPointerOffsetPair>
568 public FunctionPointerOffsetPair(IntPtr functionPointer, uint offset)
570 FunctionPointer = functionPointer;
574 public int CompareTo(FunctionPointerOffsetPair other)
578 void* fptr = FunctionPointer.ToPointer();
579 void* otherFptr = other.FunctionPointer.ToPointer();
581 if (fptr < otherFptr)
583 else if (fptr == otherFptr)
584 return Offset.CompareTo(other.Offset);
590 public readonly IntPtr FunctionPointer;
591 public readonly uint Offset;
594 private struct FunctionPointersToOffsets
596 public FunctionPointerOffsetPair[] Data;
598 public bool TryGetOffsetsRange(IntPtr functionPointer, out int firstParserOffsetIndex, out int lastParserOffsetIndex)
600 firstParserOffsetIndex = -1;
601 lastParserOffsetIndex = -1;
606 int binarySearchIndex = Array.BinarySearch(Data, new FunctionPointerOffsetPair(functionPointer, 0));
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;
614 if (binarySearchIndex >= Data.Length || Data[binarySearchIndex].FunctionPointer != functionPointer)
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)
622 lastParserOffsetIndex++;
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;
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)
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)
642 KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>[] ldFtnReverseLookup = Volatile.Read(ref ldftnReverseLookupStatic);
644 if (ldFtnReverseLookup != null)
645 return ldFtnReverseLookup;
650 ldFtnReverseLookup = Volatile.Read(ref ldftnReverseLookupStatic);
652 // double checked lock, safe due to use of volatile on s_ldftnReverseHashes
653 if (ldFtnReverseLookup != null)
654 return ldFtnReverseLookup;
656 // FUTURE: add a module load callback to invalidate this cache if a new module is loaded.
660 foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
665 ldFtnReverseLookup = new KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>[size];
667 bool restart = false;
668 foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules())
670 // If the module list changes during execution of this code, rebuild from scratch
671 if (index >= ldFtnReverseLookup.Length)
677 ldFtnReverseLookup[index] = new KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>(module, lookupComputer(module));
684 // unless we need to repeat the module enumeration, only execute the body of this while loop once.
688 Volatile.Write(ref ldftnReverseLookupStatic, ldFtnReverseLookup);
689 return ldFtnReverseLookup;
694 private KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets>[] GetLdFtnReverseLookups_InvokeMap()
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
701 internal unsafe void GetFunctionPointerAndInstantiationArgumentForOriginalLdFtnResult(IntPtr originalLdFtnResult, out IntPtr canonOriginalLdFtnResult, out IntPtr instantiationArgument)
703 if (FunctionPointerOps.IsGenericMethodPointer(originalLdFtnResult))
705 GenericMethodDescriptor* realTargetData = FunctionPointerOps.ConvertToGenericDescriptor(originalLdFtnResult);
706 canonOriginalLdFtnResult = RuntimeAugments.GetCodeTarget(realTargetData->MethodFunctionPointer);
707 instantiationArgument = realTargetData->InstantiationArgument;
711 canonOriginalLdFtnResult = RuntimeAugments.GetCodeTarget(originalLdFtnResult);
712 instantiationArgument = IntPtr.Zero;
716 internal bool TryGetMethodForOriginalLdFtnResult(IntPtr originalLdFtnResult, ref RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
718 GetFunctionPointerAndInstantiationArgumentForOriginalLdFtnResult(originalLdFtnResult, out IntPtr canonOriginalLdFtnResult, out IntPtr instantiationArgument);
720 if (instantiationArgument != IntPtr.Zero)
722 // Search TemplateMethodMap
723 if (TryGetMethodForOriginalLdFtnResult_GenericMethodWithInstantiationArgument(instantiationArgument, ref declaringTypeHandle, out methodHandle, out genericMethodTypeArgumentHandles))
728 foreach (KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets> perModuleLookup in GetLdFtnReverseLookups_InvokeMap())
733 if (perModuleLookup.Value.TryGetOffsetsRange(canonOriginalLdFtnResult, out startIndex, out endIndex))
735 for (int curIndex = startIndex; curIndex <= endIndex; curIndex++)
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))
744 methodHandle = default(QMethodDefinition);
745 genericMethodTypeArgumentHandles = null;
749 internal bool TryGetMethodForStartAddress(IntPtr methodStartAddress, ref RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle)
752 foreach (KeyValuePair<NativeFormatModuleInfo, FunctionPointersToOffsets> perModuleLookup in GetLdFtnReverseLookups_InvokeMap())
757 if (perModuleLookup.Value.TryGetOffsetsRange(methodStartAddress, out startIndex, out endIndex))
759 for (int curIndex = startIndex; curIndex <= endIndex; curIndex++)
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 _))
764 if (RuntimeAugments.IsGenericType(declaringTypeHandle))
765 declaringTypeHandle = RuntimeAugments.GetGenericDefinition(declaringTypeHandle);
772 methodHandle = default(QMethodDefinition);
776 private static FunctionPointersToOffsets ComputeLdftnReverseLookup_InvokeMap(NativeFormatModuleInfo mappingTableModule)
778 FunctionPointersToOffsets functionPointerToOffsetInInvokeMap = new FunctionPointersToOffsets();
780 NativeReader invokeMapReader;
781 if (!TryGetNativeReaderForBlob(mappingTableModule, ReflectionMapBlob.InvokeMap, out invokeMapReader))
783 return functionPointerToOffsetInInvokeMap;
786 ExternalReferencesTable externalReferences = default(ExternalReferencesTable);
787 externalReferences.InitializeCommonFixupsTable(mappingTableModule);
789 NativeParser invokeMapParser = new NativeParser(invokeMapReader, 0);
790 NativeHashtable invokeHashtable = new NativeHashtable(invokeMapParser);
792 LowLevelList<FunctionPointerOffsetPair> functionPointers = new LowLevelList<FunctionPointerOffsetPair>();
794 var lookup = invokeHashtable.EnumerateAllEntries();
795 NativeParser entryParser;
796 while (!(entryParser = lookup.GetNext()).IsNull)
798 uint parserOffset = entryParser.Offset;
799 Debug.Assert(entryParser.Reader == invokeMapParser.Reader);
801 InvokeTableFlags entryFlags = (InvokeTableFlags)entryParser.GetUnsigned();
803 bool hasEntrypoint = ((entryFlags & InvokeTableFlags.HasEntrypoint) != 0);
807 entryParser.SkipInteger(); // entryMethodHandleOrNameAndSigRaw
808 entryParser.SkipInteger(); // entryDeclaringTypeRaw
810 IntPtr entryMethodEntrypoint = externalReferences.GetFunctionPointerFromIndex(entryParser.GetUnsigned());
811 functionPointers.Add(new FunctionPointerOffsetPair(entryMethodEntrypoint, parserOffset));
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)
820 functionPointers.Add(new FunctionPointerOffsetPair(targetAddress, parserOffset));
822 IntPtr targetAddress2;
823 if (TypeLoaderEnvironment.TryGetTargetOfUnboxingAndInstantiatingStub(entryMethodEntrypoint, out targetAddress2) &&
824 targetAddress2 != entryMethodEntrypoint &&
825 targetAddress2 != targetAddress)
827 functionPointers.Add(new FunctionPointerOffsetPair(targetAddress2, parserOffset));
831 functionPointerToOffsetInInvokeMap.Data = functionPointers.ToArray();
832 Array.Sort(functionPointerToOffsetInInvokeMap.Data);
834 return functionPointerToOffsetInInvokeMap;
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)
839 methodHandle = default(QMethodDefinition);
840 genericMethodTypeArgumentHandles = null;
842 NativeReader invokeMapReader;
843 if (!TryGetNativeReaderForBlob(mappingTableModule, ReflectionMapBlob.InvokeMap, out invokeMapReader))
845 // This should have succeeded otherwise, how did we get a parser offset as an input parameter?
850 ExternalReferencesTable externalReferences = default(ExternalReferencesTable);
851 externalReferences.InitializeCommonFixupsTable(mappingTableModule);
853 NativeParser entryParser = new NativeParser(invokeMapReader, parserOffset);
855 InvokeTableFlags entryFlags = (InvokeTableFlags)entryParser.GetUnsigned();
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)))
862 Debug.Assert((entryFlags & InvokeTableFlags.HasEntrypoint) != 0);
864 uint entryMethodHandleOrNameAndSigRaw = entryParser.GetUnsigned();
865 uint entryDeclaringTypeRaw = entryParser.GetUnsigned();
867 IntPtr entryMethodEntrypoint = externalReferences.GetFunctionPointerFromIndex(entryParser.GetUnsigned());
869 if ((entryFlags & InvokeTableFlags.NeedsParameterInterpretation) == 0)
870 entryParser.SkipInteger(); // skip dynamic invoke cookie
874 declaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryDeclaringTypeRaw);
879 IntPtr targetAddress;
880 Debug.Assert(entryMethodEntrypoint == canonOriginalLdFtnResult ||
881 RuntimeAugments.GetCodeTarget(entryMethodEntrypoint) == canonOriginalLdFtnResult ||
882 TypeLoaderEnvironment.TryGetTargetOfUnboxingAndInstantiatingStub(entryMethodEntrypoint, out targetAddress) &&
883 targetAddress == canonOriginalLdFtnResult);
886 if ((entryFlags & InvokeTableFlags.RequiresInstArg) == 0 && declaringTypeHandle.IsNull())
887 declaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryDeclaringTypeRaw);
889 if ((entryFlags & InvokeTableFlags.IsGenericMethod) != 0)
891 if ((entryFlags & InvokeTableFlags.RequiresInstArg) != 0)
893 MethodNameAndSignature dummyNameAndSignature;
894 bool success = TypeLoaderEnvironment.Instance.TryGetGenericMethodComponents(instantiationArgument, out declaringTypeHandle, out dummyNameAndSignature, out genericMethodTypeArgumentHandles);
895 Debug.Assert(success);
898 genericMethodTypeArgumentHandles = GetTypeSequence(ref externalReferences, ref entryParser);
902 genericMethodTypeArgumentHandles = null;
903 if ((entryFlags & InvokeTableFlags.RequiresInstArg) != 0)
904 declaringTypeHandle = RuntimeAugments.CreateRuntimeTypeHandle(instantiationArgument);
907 RuntimeTypeHandle entryType = externalReferences.GetRuntimeTypeHandleFromIndex(entryDeclaringTypeRaw);
908 declaringTypeHandle = GetExactDeclaringType(entryType, declaringTypeHandle);
911 if ((entryFlags & InvokeTableFlags.HasMetadataHandle) != 0)
913 RuntimeTypeHandle declaringTypeHandleDefinition = GetTypeDefinition(declaringTypeHandle);
914 QTypeDefinition qTypeDefinition;
915 if (!TryGetMetadataForNamedType(declaringTypeHandleDefinition, out qTypeDefinition))
917 RuntimeExceptionHelpers.FailFast("Unable to resolve named type to having a metadata reader");
920 MethodHandle nativeFormatMethodHandle =
921 (((int)HandleType.Method << 24) | (int)entryMethodHandleOrNameAndSigRaw).AsMethodHandle();
923 methodHandle = new QMethodDefinition(qTypeDefinition.NativeFormatReader, nativeFormatMethodHandle);
927 uint nameAndSigOffset = entryMethodHandleOrNameAndSigRaw;
928 MethodNameAndSignature nameAndSig;
929 if (!TypeLoaderEnvironment.Instance.TryGetMethodNameAndSignatureFromNativeLayoutOffset(mappingTableModule.Handle, nameAndSigOffset, out nameAndSig))
935 if (!TypeLoaderEnvironment.Instance.TryGetMetadataForTypeMethodNameAndSignature(declaringTypeHandle, nameAndSig, out methodHandle))
945 private static unsafe bool TryGetMethodForOriginalLdFtnResult_GenericMethodWithInstantiationArgument(IntPtr instantiationArgument, ref RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
947 MethodNameAndSignature nameAndSig;
948 bool success = TypeLoaderEnvironment.Instance.TryGetGenericMethodComponents(instantiationArgument, out declaringTypeHandle, out nameAndSig, out genericMethodTypeArgumentHandles);
951 if (TypeLoaderEnvironment.Instance.TryGetMetadataForTypeMethodNameAndSignature(declaringTypeHandle, nameAndSig, out methodHandle))
957 methodHandle = default(QMethodDefinition);
962 public sealed override FieldAccessor TryGetFieldAccessor(
963 MetadataReader metadataReader,
964 RuntimeTypeHandle declaringTypeHandle,
965 RuntimeTypeHandle fieldTypeHandle,
966 FieldHandle fieldHandle)
968 FieldAccessMetadata fieldAccessMetadata;
970 if (!TypeLoaderEnvironment.TryGetFieldAccessMetadata(
974 out fieldAccessMetadata))
979 FieldTableFlags fieldBase = fieldAccessMetadata.Flags & FieldTableFlags.StorageClass;
982 case FieldTableFlags.Instance:
984 int fieldOffsetDelta = RuntimeAugments.IsValueType(declaringTypeHandle) ? IntPtr.Size : 0;
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);
996 case FieldTableFlags.NonGCStatic:
997 case FieldTableFlags.GCStatic:
998 case FieldTableFlags.ThreadStatic:
1003 if (RuntimeAugments.IsGenericType(declaringTypeHandle))
1007 fieldOffset = fieldAccessMetadata.Offset;
1008 staticsBase = fieldBase switch
1010 FieldTableFlags.GCStatic => TypeLoaderEnvironment.Instance.TryGetGcStaticFieldData(declaringTypeHandle),
1011 FieldTableFlags.NonGCStatic => TypeLoaderEnvironment.Instance.TryGetNonGcStaticFieldData(declaringTypeHandle),
1012 _ => TypeLoaderEnvironment.Instance.TryGetThreadStaticFieldData(declaringTypeHandle),
1018 Debug.Assert((fieldAccessMetadata.Flags & FieldTableFlags.IsUniversalCanonicalEntry) == 0);
1020 if (fieldBase != FieldTableFlags.NonGCStatic)
1022 fieldOffset = fieldAccessMetadata.Offset;
1023 staticsBase = fieldAccessMetadata.Cookie;
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.
1030 staticsBase = fieldAccessMetadata.Cookie;
1034 IntPtr cctorContext = TryGetStaticClassConstructionContext(declaringTypeHandle);
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);
1048 // This resolves RuntimeMethodHandles for methods declared on non-generic types (declaringTypeHandle is an output of this method.)
1050 public sealed override unsafe bool TryGetMethodFromHandle(RuntimeMethodHandle runtimeMethodHandle, out RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
1052 MethodNameAndSignature nameAndSignature;
1053 methodHandle = default(QMethodDefinition);
1054 if (!TypeLoaderEnvironment.Instance.TryGetRuntimeMethodHandleComponents(runtimeMethodHandle, out declaringTypeHandle, out nameAndSignature, out genericMethodTypeArgumentHandles))
1057 return TypeLoaderEnvironment.Instance.TryGetMetadataForTypeMethodNameAndSignature(declaringTypeHandle, nameAndSignature, out methodHandle);
1061 // This resolves RuntimeMethodHandles for methods declared on generic types (declaringTypeHandle is an input of this method.)
1063 public sealed override bool TryGetMethodFromHandleAndType(RuntimeMethodHandle runtimeMethodHandle, RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles)
1065 return TryGetMethodFromHandle(runtimeMethodHandle, out _, out methodHandle, out genericMethodTypeArgumentHandles);
1069 // This resolves RuntimeFieldHandles for fields declared on non-generic types (declaringTypeHandle is an output of this method.)
1071 public sealed override unsafe bool TryGetFieldFromHandle(RuntimeFieldHandle runtimeFieldHandle, out RuntimeTypeHandle declaringTypeHandle, out FieldHandle fieldHandle)
1073 fieldHandle = default(FieldHandle);
1076 if (!TypeLoaderEnvironment.Instance.TryGetRuntimeFieldHandleComponents(runtimeFieldHandle, out declaringTypeHandle, out fieldName))
1079 QTypeDefinition qTypeDefinition;
1080 RuntimeTypeHandle metadataLookupTypeHandle = GetTypeDefinition(declaringTypeHandle);
1082 if (!TryGetMetadataForNamedType(metadataLookupTypeHandle, out qTypeDefinition))
1085 // TODO! Handle ecma style types
1086 MetadataReader reader = qTypeDefinition.NativeFormatReader;
1087 TypeDefinitionHandle typeDefinitionHandle = qTypeDefinition.NativeFormatHandle;
1089 TypeDefinition typeDefinition = typeDefinitionHandle.GetTypeDefinition(reader);
1090 foreach (FieldHandle fh in typeDefinition.Fields)
1092 Field field = fh.GetField(reader);
1093 if (field.Name.StringEquals(fieldName, reader))
1104 // This resolves RuntimeFieldHandles for fields declared on generic types (declaringTypeHandle is an input of this method.)
1106 public sealed override bool TryGetFieldFromHandleAndType(RuntimeFieldHandle runtimeFieldHandle, RuntimeTypeHandle declaringTypeHandle, out FieldHandle fieldHandle)
1108 return TryGetFieldFromHandle(runtimeFieldHandle, out _, out fieldHandle);
1112 /// Locate the static constructor context given the runtime type handle (MethodTable) for the type in question.
1114 /// <param name="typeHandle">MethodTable of the type to look up</param>
1115 internal static unsafe IntPtr TryGetStaticClassConstructionContext(RuntimeTypeHandle typeHandle)
1117 return TypeLoaderEnvironment.TryGetStaticClassConstructionContext(typeHandle);
1120 private struct MethodParametersInfo
1122 private MetadataReader _metadataReader;
1123 private MethodBase _methodBase;
1124 private MethodHandle _methodHandle;
1126 private Handle[] _returnTypeAndParametersHandlesCache;
1127 private Type[] _returnTypeAndParametersTypesCache;
1129 public MethodParametersInfo(MethodBase methodBase)
1131 _metadataReader = null;
1132 _methodBase = methodBase;
1133 _methodHandle = default(MethodHandle);
1134 _returnTypeAndParametersHandlesCache = null;
1135 _returnTypeAndParametersTypesCache = null;
1138 public MethodParametersInfo(MetadataReader metadataReader, MethodBase methodBase, MethodHandle methodHandle)
1140 _metadataReader = metadataReader;
1141 _methodBase = methodBase;
1142 _methodHandle = methodHandle;
1143 _returnTypeAndParametersHandlesCache = null;
1144 _returnTypeAndParametersTypesCache = null;
1147 public LowLevelList<RuntimeTypeHandle> ParameterTypeHandles
1151 ParameterInfo[] parameters = _methodBase.GetParametersNoCopy();
1152 LowLevelList<RuntimeTypeHandle> result = new LowLevelList<RuntimeTypeHandle>(parameters.Length);
1154 for (int i = 0; i < parameters.Length; i++)
1156 Type parameterType = parameters[i].ParameterType;
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);
1163 result.Add(parameterType.TypeHandle);
1170 public RuntimeTypeHandle ReturnTypeHandle
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;
1182 public LowLevelList<RuntimeTypeHandle> ReturnTypeAndParameterTypeHandles
1186 LowLevelList<RuntimeTypeHandle> result = ParameterTypeHandles;
1187 result.Insert(0, ReturnTypeHandle);
1192 public bool[] ReturnTypeAndParametersByRefFlags
1196 ParameterInfo[] parameters = _methodBase.GetParametersNoCopy();
1197 bool[] result = new bool[parameters.Length + 1];
1199 MethodInfo reflectionMethodInfo = _methodBase as MethodInfo;
1200 Type returnType = reflectionMethodInfo != null ? reflectionMethodInfo.ReturnType : typeof(void);
1201 result[0] = returnType.IsByRef;
1203 for (int i = 0; i < parameters.Length; i++)
1204 result[i + 1] = parameters[i].ParameterType.IsByRef;
1210 private void GetReturnTypeAndParameterTypesAndMDHandles(ref Handle[] handles, ref Type[] types)
1212 if (_returnTypeAndParametersTypesCache == null)
1214 Debug.Assert(_metadataReader != null && !_methodHandle.Equals(default(MethodHandle)));
1216 _returnTypeAndParametersHandlesCache = new Handle[_methodBase.GetParametersNoCopy().Length + 1];
1217 _returnTypeAndParametersTypesCache = new Type[_methodBase.GetParametersNoCopy().Length + 1];
1219 MethodSignature signature = _methodHandle.GetMethod(_metadataReader).Signature.GetMethodSignature(_metadataReader);
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;
1226 // Check the method parameters for generic vars
1228 foreach (Handle paramSigHandle in signature.Parameters)
1230 _returnTypeAndParametersHandlesCache[index] = paramSigHandle;
1231 _returnTypeAndParametersTypesCache[index] = _methodBase.GetParametersNoCopy()[index - 1].ParameterType;
1236 handles = _returnTypeAndParametersHandlesCache;
1237 types = _returnTypeAndParametersTypesCache;
1238 Debug.Assert(handles != null && types != null);