public unsafe bool TryGetMetadataForNamedType(RuntimeTypeHandle runtimeTypeHandle, out MetadataReader metadataReader, out TypeDefinitionHandle typeDefHandle) { // Iterate over all modules, starting with the module that defines the EEType foreach (IntPtr moduleHandle in ModuleList.Enumerate(RuntimeAugments.GetModuleFromTypeHandle(runtimeTypeHandle))) { NativeReader typeMapReader; if (TryGetNativeReaderForBlob(moduleHandle, ReflectionMapBlob.TypeMap, out typeMapReader)) { NativeParser typeMapParser = new NativeParser(typeMapReader, 0); NativeHashtable typeHashtable = new NativeHashtable(typeMapParser); ExternalReferencesTable externalReferences = default(ExternalReferencesTable); externalReferences.InitializeCommonFixupsTable(moduleHandle); var lookup = typeHashtable.Lookup(runtimeTypeHandle.GetHashCode()); NativeParser entryParser; while (!(entryParser = lookup.GetNext()).IsNull) { RuntimeTypeHandle foundType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); if (foundType.Equals(runtimeTypeHandle)) { Handle entryMetadataHandle = entryParser.GetUnsigned().AsHandle(); if (entryMetadataHandle.HandleType == HandleType.TypeDefinition) { metadataReader = ModuleList.Instance.GetMetadataReaderForModule(moduleHandle); typeDefHandle = entryMetadataHandle.ToTypeDefinitionHandle(metadataReader); return true; } } } } } metadataReader = null; typeDefHandle = default(TypeDefinitionHandle); return false; }
internal AllEntriesEnumerator(NativeHashtable table) { _table = table; _currentBucket = 0; _parser = _table.GetParserForBucket(_currentBucket, out _endOffset); }
private unsafe bool ResolveGenericVirtualMethodTarget_Static(RuntimeTypeHandle targetTypeHandle, RuntimeTypeHandle declaringType, RuntimeTypeHandle[] genericArguments, MethodNameAndSignature callingMethodNameAndSignature, out IntPtr methodPointer, out IntPtr dictionaryPointer) { methodPointer = dictionaryPointer = IntPtr.Zero; // Get the open type definition of the containing type of the generic virtual method being resolved RuntimeTypeHandle openCallingTypeHandle = GetTypeDefinition(declaringType); // Get the open type definition of the current type of the object instance on which the GVM is being resolved RuntimeTypeHandle openTargetTypeHandle = GetTypeDefinition(targetTypeHandle); int hashCode = openCallingTypeHandle.GetHashCode(); hashCode = ((hashCode << 13) ^ hashCode) ^ openTargetTypeHandle.GetHashCode(); #if REFLECTION_EXECUTION_TRACE ReflectionExecutionLogger.WriteLine("GVM Target Resolution = " + GetTypeNameDebug(targetTypeHandle) + "." + callingMethodNameAndSignature.Name); #endif foreach (IntPtr moduleHandle in ModuleList.Enumerate(RuntimeAugments.GetModuleFromTypeHandle(openTargetTypeHandle))) { NativeReader gvmTableReader; if (!TryGetNativeReaderForBlob(moduleHandle, ReflectionMapBlob.GenericVirtualMethodTable, out gvmTableReader)) continue; NativeReader nativeLayoutReader; if (!TryGetNativeReaderForBlob(moduleHandle, ReflectionMapBlob.NativeLayoutInfo, out nativeLayoutReader)) continue; NativeParser gvmTableParser = new NativeParser(gvmTableReader, 0); NativeHashtable gvmHashtable = new NativeHashtable(gvmTableParser); ExternalReferencesTable extRefs = default(ExternalReferencesTable); extRefs.InitializeCommonFixupsTable(moduleHandle); var lookup = gvmHashtable.Lookup(hashCode); NativeParser entryParser; while (!(entryParser = lookup.GetNext()).IsNull) { RuntimeTypeHandle parsedCallingTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); if (!parsedCallingTypeHandle.Equals(openCallingTypeHandle)) continue; RuntimeTypeHandle parsedTargetTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); if (!parsedTargetTypeHandle.Equals(openTargetTypeHandle)) continue; uint parsedCallingNameAndSigToken = extRefs.GetRvaFromIndex(entryParser.GetUnsigned()); MethodNameAndSignature parsedCallingNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, parsedCallingNameAndSigToken); if (!parsedCallingNameAndSignature.Equals(callingMethodNameAndSignature)) continue; uint parsedTargetMethodNameAndSigToken = extRefs.GetRvaFromIndex(entryParser.GetUnsigned()); MethodNameAndSignature targetMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, parsedTargetMethodNameAndSigToken); Debug.Assert(targetMethodNameAndSignature != null); return TryGetGenericVirtualMethodPointer(targetTypeHandle, targetMethodNameAndSignature, genericArguments, out methodPointer, out dictionaryPointer); } } return false; }
private bool ResolveInterfaceGenericVirtualMethodSlot_Static(RuntimeTypeHandle targetTypeHandle, ref RuntimeTypeHandle declaringType, ref MethodNameAndSignature methodNameAndSignature) { // Get the open type definition of the containing type of the generic virtual method being resolved RuntimeTypeHandle openCallingTypeHandle = GetTypeDefinition(declaringType); // Get the open type definition of the current type of the object instance on which the GVM is being resolved RuntimeTypeHandle openTargetTypeHandle; RuntimeTypeHandle[] targetTypeInstantiation; openTargetTypeHandle = GetOpenTypeDefinition(targetTypeHandle, out targetTypeInstantiation); #if REFLECTION_EXECUTION_TRACE ReflectionExecutionLogger.WriteLine("INTERFACE GVM call = " + GetTypeNameDebug(declaringType) + "." + methodNameAndSignature.Name); #endif foreach (IntPtr moduleHandle in ModuleList.Enumerate(RuntimeAugments.GetModuleFromTypeHandle(openTargetTypeHandle))) { NativeReader gvmTableReader; if (!TryGetNativeReaderForBlob(moduleHandle, ReflectionMapBlob.InterfaceGenericVirtualMethodTable, out gvmTableReader)) continue; NativeReader nativeLayoutReader; if (!TryGetNativeReaderForBlob(moduleHandle, ReflectionMapBlob.NativeLayoutInfo, out nativeLayoutReader)) continue; NativeParser gvmTableParser = new NativeParser(gvmTableReader, 0); NativeHashtable gvmHashtable = new NativeHashtable(gvmTableParser); ExternalReferencesTable extRefs = default(ExternalReferencesTable); extRefs.InitializeCommonFixupsTable(moduleHandle); var lookup = gvmHashtable.Lookup(openCallingTypeHandle.GetHashCode()); NativeParser entryParser; while (!(entryParser = lookup.GetNext()).IsNull) { RuntimeTypeHandle interfaceTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); if (!openCallingTypeHandle.Equals(interfaceTypeHandle)) continue; uint nameAndSigToken = extRefs.GetRvaFromIndex(entryParser.GetUnsigned()); MethodNameAndSignature interfaceMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, nameAndSigToken); if (!interfaceMethodNameAndSignature.Equals(methodNameAndSignature)) continue; // For each of the possible GVM slot targets for the current interface call, we will do the following: // // Step 1: Scan the types that currently provide implementations for the current GVM slot target, and look // for ones that match the target object's type. // // Step 2: For each type that we find in step #1, get a list of all the interfaces that the current GVM target // provides an implementation for // // Step 3: For each interface in the list in step #2, parse the signature of that interface, do the generic argument // substitution (in case of a generic interface), and check if this interface signature is assignable from the // calling interface signature (from the name and sig input). if there is an exact match based on // interface type, then we've found the right slot. Otherwise, re-scan the entry again and see if some interface // type is compatible with the initial slots interface by means of variance. // This is done by calling the TypeLoaderEnvironment helper function. // // Example: // public interface IFoo<out T, out U> // { // string M1<V>(); // } // public class Foo1<T, U> : IFoo<T, U>, IFoo<Kvp<T, string>, U> // { // string IFoo<T, U>.M1<V>() { ... } // public virtual string M1<V>() { ... } // } // public class Foo2<T, U> : Foo1<object, U>, IFoo<U, T> // { // string IFoo<U, T>.M1<V>() { ... } // } // // GVM Table layout for IFoo<T, U>.M1<V>: // { // InterfaceTypeHandle = IFoo<T, U> // InterfaceMethodNameAndSignature = { "M1", SigOf(string M1) } // GVMTargetSlots[] = // { // { // TargetMethodNameAndSignature = { "M1", SigOf(M1) } // TargetTypeHandle = Foo1<T, U> // ImplementingTypes[] = { // ImplementingTypeHandle = Foo1<T, U> // ImplementedInterfacesSignatures[] = { SigOf(IFoo<!0, !1>) } // } // }, // // { // TargetMethodNameAndSignature = { "M1", SigOf(M1) } // TargetTypeHandle = Foo1<T, U> // ImplementingTypes[] = { // ImplementingTypeHandle = Foo1<T, U> // ImplementedInterfacesSignatures[] = { SigOf(IFoo<Kvp<!0, string>, !1>) } // } // }, // // { // TargetMethodNameAndSignature = { "M1", SigOf(M1) } // TargetTypeHandle = Foo2<T, U> // ImplementingTypes = { // ImplementingTypeHandle = Foo2<T, U> // ImplementedInterfacesSignatures[] = { SigOf(IFoo<!1, !0>) } // } // }, // } // } // uint currentOffset = entryParser.Offset; // Non-variant dispatch of a variant generic interface generic virtual method. if (FindMatchingInterfaceSlot(moduleHandle, nativeLayoutReader, ref entryParser, ref extRefs, ref declaringType, ref methodNameAndSignature, openTargetTypeHandle, targetTypeInstantiation, false)) { return true; } entryParser.Offset = currentOffset; // Variant dispatch of a variant generic interface generic virtual method. if (FindMatchingInterfaceSlot(moduleHandle, nativeLayoutReader, ref entryParser, ref extRefs, ref declaringType, ref methodNameAndSignature, openTargetTypeHandle, targetTypeInstantiation, true)) { return true; } } } return false; }
public unsafe bool TryGetNamedTypeForMetadata(MetadataReader metadataReader, TypeDefinitionHandle typeDefHandle, out RuntimeTypeHandle runtimeTypeHandle) { int hashCode = typeDefHandle.ComputeHashCode(metadataReader); IntPtr moduleHandle = ModuleList.Instance.GetModuleForMetadataReader(metadataReader); NativeReader typeMapReader; if (TryGetNativeReaderForBlob(moduleHandle, ReflectionMapBlob.TypeMap, out typeMapReader)) { NativeParser typeMapParser = new NativeParser(typeMapReader, 0); NativeHashtable typeHashtable = new NativeHashtable(typeMapParser); ExternalReferencesTable externalReferences = default(ExternalReferencesTable); externalReferences.InitializeCommonFixupsTable(moduleHandle); var lookup = typeHashtable.Lookup(hashCode); NativeParser entryParser; while (!(entryParser = lookup.GetNext()).IsNull) { var foundTypeIndex = entryParser.GetUnsigned(); if (entryParser.GetUnsigned().AsHandle().Equals(typeDefHandle)) { runtimeTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(foundTypeIndex); return true; } } } runtimeTypeHandle = default(RuntimeTypeHandle); return false; }
// get the statics hash table, external references, and static info table for a module // TODO multi-file: consider whether we want to cache this info private unsafe bool GetStaticsInfoHashtable(IntPtr moduleHandle, out NativeHashtable staticsInfoHashtable, out ExternalReferencesTable externalReferencesLookup, out ExternalReferencesTable staticInfoLookup) { byte* pBlob; uint cbBlob; staticsInfoHashtable = default(NativeHashtable); externalReferencesLookup = default(ExternalReferencesTable); staticInfoLookup = default(ExternalReferencesTable); // Load statics info hashtable if (!RuntimeAugments.FindBlob(moduleHandle, (int)ReflectionMapBlob.StaticsInfoHashtable, new IntPtr(&pBlob), new IntPtr(&cbBlob))) return false; NativeReader reader = new NativeReader(pBlob, cbBlob); NativeParser parser = new NativeParser(reader, 0); if (!externalReferencesLookup.InitializeNativeReferences(moduleHandle)) return false; if (!staticInfoLookup.InitializeNativeStatics(moduleHandle)) return false; staticsInfoHashtable = new NativeHashtable(parser); return true; }
// get the generics hash table and external references table for a module // TODO multi-file: consider whether we want to cache this info private unsafe bool GetHashtableFromBlob(IntPtr moduleHandle, ReflectionMapBlob blobId, out NativeHashtable hashtable, out ExternalReferencesTable externalReferencesLookup) { byte* pBlob; uint cbBlob; hashtable = default(NativeHashtable); externalReferencesLookup = default(ExternalReferencesTable); if (!RuntimeAugments.FindBlob(moduleHandle, (int)blobId, new IntPtr(&pBlob), new IntPtr(&cbBlob))) return false; NativeReader reader = new NativeReader(pBlob, cbBlob); NativeParser parser = new NativeParser(reader, 0); hashtable = new NativeHashtable(parser); return externalReferencesLookup.InitializeNativeReferences(moduleHandle); }
/// <summary> /// Try to look up non-gc/gc static effective field bases for a non-generic non-dynamic type. /// </summary> /// <param name="declaringTypeHandle">Declaring type for the method</param> /// <param name="fieldAccessKind">type of static base to find</param> /// <param name="staticsRegionAddress">Output - statics region address info</param> /// <returns>true when found, false otherwise</returns> private static unsafe bool TryGetStaticFieldBaseFromFieldAccessMap( RuntimeTypeHandle declaringTypeHandle, FieldAccessStaticDataKind fieldAccessKind, out IntPtr staticsRegionAddress) { staticsRegionAddress = IntPtr.Zero; byte* comparableStaticRegionAddress = null; CanonicallyEquivalentEntryLocator canonWrapper = new CanonicallyEquivalentEntryLocator(declaringTypeHandle, CanonicalFormKind.Specific); // This function only finds results for non-dynamic, non-generic types if (RuntimeAugments.IsDynamicType(declaringTypeHandle) || RuntimeAugments.IsGenericType(declaringTypeHandle)) return false; foreach (IntPtr mappingTableModule in ModuleList.Enumerate(RuntimeAugments.GetModuleFromTypeHandle(declaringTypeHandle))) { NativeReader fieldMapReader; if (!TryGetNativeReaderForBlob(mappingTableModule, ReflectionMapBlob.FieldAccessMap, out fieldMapReader)) continue; NativeParser fieldMapParser = new NativeParser(fieldMapReader, 0); NativeHashtable fieldHashtable = new NativeHashtable(fieldMapParser); ExternalReferencesTable externalReferences = default(ExternalReferencesTable); if (!externalReferences.InitializeCommonFixupsTable(mappingTableModule)) { continue; } var lookup = fieldHashtable.Lookup(canonWrapper.LookupHashCode); NativeParser entryParser; while (!(entryParser = lookup.GetNext()).IsNull) { // Grammar of a hash table entry: // Flags + DeclaringType + MdHandle or Name + Cookie or Ordinal or Offset FieldTableFlags entryFlags = (FieldTableFlags)entryParser.GetUnsigned(); Debug.Assert(!entryFlags.HasFlag(FieldTableFlags.IsUniversalCanonicalEntry)); if (!entryFlags.HasFlag(FieldTableFlags.Static)) continue; switch (fieldAccessKind) { case FieldAccessStaticDataKind.NonGC: if (entryFlags.HasFlag(FieldTableFlags.IsGcSection)) continue; if (entryFlags.HasFlag(FieldTableFlags.ThreadStatic)) continue; break; case FieldAccessStaticDataKind.GC: if (!entryFlags.HasFlag(FieldTableFlags.IsGcSection)) continue; if (entryFlags.HasFlag(FieldTableFlags.ThreadStatic)) continue; break; case FieldAccessStaticDataKind.TLS: default: // TODO! TLS statics Environment.FailFast("TLS static field access not yet supported"); return false; } RuntimeTypeHandle entryDeclaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); if (!entryDeclaringTypeHandle.Equals(declaringTypeHandle)) continue; if (entryFlags.HasFlag(FieldTableFlags.HasMetadataHandle)) { // skip metadata handle entryParser.GetUnsigned(); } else { // skip field name entryParser.SkipString(); } int cookieOrOffsetOrOrdinal = (int)entryParser.GetUnsigned(); int fieldOffset = (int)externalReferences.GetRvaFromIndex((uint)cookieOrOffsetOrOrdinal); IntPtr fieldAddress = RvaToNonGenericStaticFieldAddress( mappingTableModule, fieldOffset); if ((comparableStaticRegionAddress == null) || (comparableStaticRegionAddress > fieldAddress.ToPointer())) { comparableStaticRegionAddress = (byte*)fieldAddress.ToPointer(); } } // Static fields for a type can only be found in at most one module if (comparableStaticRegionAddress != null) break; } if (comparableStaticRegionAddress != null) { staticsRegionAddress = new IntPtr(comparableStaticRegionAddress); return true; } else { return false; } }
/// <summary> /// Try to look up field acccess info for given canon in metadata blobs for all available modules. /// </summary> /// <param name="metadataReader">Metadata reader for the declaring type</param> /// <param name="declaringTypeHandle">Declaring type for the method</param> /// <param name="fieldHandle">Field handle</param> /// <param name="canonFormKind">Canonical form to use</param> /// <param name="fieldAccessMetadata">Output - metadata information for field accessor construction</param> /// <returns>true when found, false otherwise</returns> private static bool TryGetFieldAccessMetadataFromFieldAccessMap( MetadataReader metadataReader, RuntimeTypeHandle declaringTypeHandle, FieldHandle fieldHandle, CanonicalFormKind canonFormKind, ref FieldAccessMetadata fieldAccessMetadata) { CanonicallyEquivalentEntryLocator canonWrapper = new CanonicallyEquivalentEntryLocator(declaringTypeHandle, canonFormKind); IntPtr fieldHandleModule = ModuleList.Instance.GetModuleForMetadataReader(metadataReader); bool isDynamicType = RuntimeAugments.IsDynamicType(declaringTypeHandle); string fieldName = null; RuntimeTypeHandle declaringTypeHandleDefinition = Instance.GetTypeDefinition(declaringTypeHandle); foreach (IntPtr mappingTableModule in ModuleList.Enumerate(RuntimeAugments.GetModuleFromTypeHandle(declaringTypeHandle))) { NativeReader fieldMapReader; if (!TryGetNativeReaderForBlob(mappingTableModule, ReflectionMapBlob.FieldAccessMap, out fieldMapReader)) continue; NativeParser fieldMapParser = new NativeParser(fieldMapReader, 0); NativeHashtable fieldHashtable = new NativeHashtable(fieldMapParser); ExternalReferencesTable externalReferences = default(ExternalReferencesTable); if (!externalReferences.InitializeCommonFixupsTable(mappingTableModule)) { continue; } var lookup = fieldHashtable.Lookup(canonWrapper.LookupHashCode); NativeParser entryParser; while (!(entryParser = lookup.GetNext()).IsNull) { // Grammar of a hash table entry: // Flags + DeclaringType + MdHandle or Name + Cookie or Ordinal or Offset FieldTableFlags entryFlags = (FieldTableFlags)entryParser.GetUnsigned(); if ((canonFormKind == CanonicalFormKind.Universal) != entryFlags.HasFlag(FieldTableFlags.IsUniversalCanonicalEntry)) continue; RuntimeTypeHandle entryDeclaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); if (!entryDeclaringTypeHandle.Equals(declaringTypeHandle) && !canonWrapper.IsCanonicallyEquivalent(entryDeclaringTypeHandle)) continue; if (entryFlags.HasFlag(FieldTableFlags.HasMetadataHandle)) { Handle entryFieldHandle = (((int)HandleType.Field << 24) | (int)entryParser.GetUnsigned()).AsHandle(); if (!fieldHandle.Equals(entryFieldHandle)) continue; } else { if (fieldName == null) { MetadataReader mdReader; TypeDefinitionHandle typeDefHandleUnused; bool success = Instance.TryGetMetadataForNamedType( declaringTypeHandleDefinition, out mdReader, out typeDefHandleUnused); Debug.Assert(success); fieldName = mdReader.GetString(fieldHandle.GetField(mdReader).Name); } string entryFieldName = entryParser.GetString(); if (fieldName != entryFieldName) continue; } int cookieOrOffsetOrOrdinal = (int)entryParser.GetUnsigned(); int fieldOffset; IntPtr fieldAddressCookie = IntPtr.Zero; if (canonFormKind == CanonicalFormKind.Universal) { if (!TypeLoaderEnvironment.Instance.TryGetFieldOffset(declaringTypeHandle, (uint)cookieOrOffsetOrOrdinal, out fieldOffset)) { Debug.Assert(false); return false; } } else { #if CORERT fieldOffset = cookieOrOffsetOrOrdinal; #else fieldOffset = (int)externalReferences.GetRvaFromIndex((uint)cookieOrOffsetOrOrdinal); #endif } if ((entryFlags & FieldTableFlags.StorageClass) == FieldTableFlags.ThreadStatic) { if (canonFormKind != CanonicalFormKind.Universal) { fieldAddressCookie = RvaToNonGenericStaticFieldAddress(mappingTableModule, fieldOffset); } if (!entryDeclaringTypeHandle.Equals(declaringTypeHandle)) { // In this case we didn't find an exact match, but we did find a canonically equivalent match // We might be in the dynamic type case, or the canonically equivalent, but not the same case. if (!RuntimeAugments.IsDynamicType(declaringTypeHandle)) { int offsetToCreateCookieFor = fieldOffset; // We're working with a statically generated type, but we didn't find an exact match in the tables if (canonFormKind != CanonicalFormKind.Universal) offsetToCreateCookieFor = checked((int)TypeLoaderEnvironment.GetThreadStaticTypeOffsetFromThreadStaticCookie(fieldAddressCookie)); fieldAddressCookie = TypeLoaderEnvironment.Instance.TryGetThreadStaticFieldOffsetCookieForTypeAndFieldOffset(declaringTypeHandle, checked((uint)offsetToCreateCookieFor)); } } } fieldAccessMetadata.MappingTableModule = mappingTableModule; fieldAccessMetadata.Cookie = fieldAddressCookie; fieldAccessMetadata.Flags = entryFlags; fieldAccessMetadata.Offset = fieldOffset; return true; } } return false; }