public bool TryLookupExactMethodPointerForComponents(RuntimeTypeHandle declaringType, MethodNameAndSignature nameAndSignature, RuntimeTypeHandle[] genericMethodArgumentHandles, out IntPtr result) { int lookupHashcode = declaringType.GetHashCode(); NativeHashtable hashtable; ExternalReferencesTable externalReferencesLookup; HandleBasedGenericMethodLookup lookupData = new HandleBasedGenericMethodLookup(declaringType, nameAndSignature, genericMethodArgumentHandles); foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules()) { if (!GetHashtableFromBlob(module, ReflectionMapBlob.ExactMethodInstantiationsHashtable, out hashtable, out externalReferencesLookup)) { continue; } var enumerator = hashtable.Lookup(lookupHashcode); NativeParser entryParser; while (!(entryParser = enumerator.GetNext()).IsNull) { if (!lookupData.MatchParsedEntry(ref entryParser, ref externalReferencesLookup, module.Handle)) { continue; } // We found a match result = externalReferencesLookup.GetIntPtrFromIndex(entryParser.GetUnsigned()); return(true); } } result = IntPtr.Zero; return(false); }
/// <summary> /// Get the NativeLayout for a type from a ReadyToRun image. /// </summary> public static bool TryGetMetadataNativeLayout(TypeDesc concreteType, out NativeFormatModuleInfo nativeLayoutInfoModule, out uint nativeLayoutInfoToken) { nativeLayoutInfoModule = null; nativeLayoutInfoToken = 0; #if SUPPORTS_NATIVE_METADATA_TYPE_LOADING var nativeMetadataType = concreteType.GetTypeDefinition() as TypeSystem.NativeFormat.NativeFormatType; if (nativeMetadataType == null) { return(false); } var canonForm = concreteType.ConvertToCanonForm(CanonicalFormKind.Specific); var hashCode = canonForm.GetHashCode(); #if SUPPORTS_R2R_LOADING foreach (var moduleInfo in ModuleList.EnumerateModules()) { if (moduleInfo.MetadataReader == null) { continue; } ExternalReferencesTable externalFixupsTable; NativeHashtable typeTemplatesHashtable = LoadHashtable(moduleInfo.Handle, ReflectionMapBlob.MetadataBasedTypeTemplateMap, out externalFixupsTable); if (typeTemplatesHashtable.IsNull) { continue; } var enumerator = typeTemplatesHashtable.Lookup(hashCode); var nativeMetadataUnit = nativeMetadataType.Context.ResolveMetadataUnit(moduleInfo); NativeParser entryParser; while (!(entryParser = enumerator.GetNext()).IsNull) { var entryTypeHandle = entryParser.GetUnsigned().AsHandle(); TypeDesc typeDesc = nativeMetadataUnit.GetType(entryTypeHandle); Debug.Assert(typeDesc != null); if (typeDesc == canonForm) { TypeLoaderLogger.WriteLine("Found metadata template for type " + concreteType.ToString() + ": " + typeDesc.ToString()); nativeLayoutInfoToken = entryParser.GetUnsigned(); if (nativeLayoutInfoToken == BadTokenFixupValue) { throw new BadImageFormatException(); } nativeLayoutInfoModule = moduleHandle; return(true); } } } #endif #endif return(false); }
private unsafe bool TryGetStaticGenericMethodComponents(IntPtr methodDictionary, out RuntimeTypeHandle declaringType, out MethodNameAndSignature methodNameAndSignature, out RuntimeTypeHandle[] genericMethodArgumentHandles) { // Generic method dictionaries have a header that has the hash code in it. Locate the header IntPtr dictionaryHeader = IntPtr.Subtract(methodDictionary, IntPtr.Size); int lookupHashcode = *(int *)dictionaryHeader; ExternalReferencesTable externalReferencesLookup; NativeHashtable genericMethodsHashtable; foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules()) { if (!GetHashtableFromBlob(module, ReflectionMapBlob.GenericMethodsHashtable, out genericMethodsHashtable, out externalReferencesLookup)) { continue; } var enumerator = genericMethodsHashtable.Lookup(lookupHashcode); NativeParser entryParser; while (!(entryParser = enumerator.GetNext()).IsNull) { // Is this entry the dictionary we are looking for? uint dictionaryIndex = entryParser.GetUnsigned(); IntPtr parsedMethodDictionary = externalReferencesLookup.GetIntPtrFromIndex(dictionaryIndex); if (parsedMethodDictionary != methodDictionary) { continue; } // We have a match - fill in the results declaringType = externalReferencesLookup.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); // Hash table names / sigs are indirected through to the native layout info if (!TypeLoaderEnvironment.Instance.TryGetMethodNameAndSignatureFromNativeLayoutOffset(module.Handle, entryParser.GetUnsigned(), out methodNameAndSignature)) { continue; } uint arity = entryParser.GetSequenceCount(); genericMethodArgumentHandles = new RuntimeTypeHandle[arity]; for (int i = 0; i < arity; i++) { genericMethodArgumentHandles[i] = externalReferencesLookup.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); } return(true); } } declaringType = default(RuntimeTypeHandle); methodNameAndSignature = null; genericMethodArgumentHandles = null; return(false); }
public bool CompareMethodSignatures(RuntimeSignature signature1, RuntimeSignature signature2) { if (signature1.IsNativeLayoutSignature && signature2.IsNativeLayoutSignature) { if (signature1.StructuralEquals(signature2)) { return(true); } NativeFormatModuleInfo module1 = ModuleList.GetModuleInfoByHandle(new TypeManagerHandle(signature1.ModuleHandle)); NativeReader reader1 = GetNativeLayoutInfoReader(signature1); NativeParser parser1 = new NativeParser(reader1, signature1.NativeLayoutOffset); NativeFormatModuleInfo module2 = ModuleList.GetModuleInfoByHandle(new TypeManagerHandle(signature2.ModuleHandle)); NativeReader reader2 = GetNativeLayoutInfoReader(signature2); NativeParser parser2 = new NativeParser(reader2, signature2.NativeLayoutOffset); return(CompareMethodSigs(parser1, module1, parser2, module2)); } else if (signature1.IsNativeLayoutSignature) { int token = signature2.Token; MetadataReader metadataReader = ModuleList.Instance.GetMetadataReaderForModule(new TypeManagerHandle(signature2.ModuleHandle)); MethodSignatureComparer comparer = new MethodSignatureComparer(metadataReader, token.AsHandle().ToMethodHandle(metadataReader)); return(comparer.IsMatchingNativeLayoutMethodSignature(signature1)); } else if (signature2.IsNativeLayoutSignature) { int token = signature1.Token; MetadataReader metadataReader = ModuleList.Instance.GetMetadataReaderForModule(new TypeManagerHandle(signature1.ModuleHandle)); MethodSignatureComparer comparer = new MethodSignatureComparer(metadataReader, token.AsHandle().ToMethodHandle(metadataReader)); return(comparer.IsMatchingNativeLayoutMethodSignature(signature2)); } else { // For now, RuntimeSignatures are only used to compare for method signature equality (along with their Name) // So we can implement this with the simple equals check if (signature1.Token != signature2.Token) { return(false); } if (signature1.ModuleHandle != signature2.ModuleHandle) { return(false); } return(true); } }
private static TypeDesc TryGetTypeTemplate_Internal(TypeDesc concreteType, CanonicalFormKind kind, out NativeFormatModuleInfo nativeLayoutInfoModule, out uint nativeLayoutInfoToken) { nativeLayoutInfoModule = null; nativeLayoutInfoToken = 0; var canonForm = concreteType.ConvertToCanonForm(kind); var hashCode = canonForm.GetHashCode(); foreach (NativeFormatModuleInfo moduleInfo in ModuleList.EnumerateModules()) { ExternalReferencesTable externalFixupsTable; NativeHashtable typeTemplatesHashtable = LoadHashtable(moduleInfo, ReflectionMapBlob.TypeTemplateMap, out externalFixupsTable); if (typeTemplatesHashtable.IsNull) { continue; } var enumerator = typeTemplatesHashtable.Lookup(hashCode); NativeParser entryParser; while (!(entryParser = enumerator.GetNext()).IsNull) { RuntimeTypeHandle candidateTemplateTypeHandle = externalFixupsTable.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); TypeDesc candidateTemplate = concreteType.Context.ResolveRuntimeTypeHandle(candidateTemplateTypeHandle); if (canonForm == candidateTemplate.ConvertToCanonForm(kind)) { TypeLoaderLogger.WriteLine("Found template for type " + concreteType.ToString() + ": " + candidateTemplate.ToString()); nativeLayoutInfoToken = entryParser.GetUnsigned(); if (nativeLayoutInfoToken == BadTokenFixupValue) { // TODO: once multifile gets fixed up, make this throw a BadImageFormatException TypeLoaderLogger.WriteLine("ERROR: template not fixed up, skipping"); continue; } Debug.Assert( (kind != CanonicalFormKind.Universal) || (kind == CanonicalFormKind.Universal && candidateTemplate == candidateTemplate.ConvertToCanonForm(kind))); nativeLayoutInfoModule = moduleInfo; return(candidateTemplate); } } } TypeLoaderLogger.WriteLine("ERROR: Cannot find a suitable template for type " + concreteType.ToString()); return(null); }
protected override NamedTypeLookupResult CreateValueFromKey(RuntimeTypeHandle key) { int hashCode = GetKeyHashCode(key); // Iterate over all modules, starting with the module that defines the EEType foreach (IntPtr moduleHandle in ModuleList.Enumerate(RuntimeAugments.GetModuleFromTypeHandle(key))) { 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) { RuntimeTypeHandle foundType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); if (foundType.Equals(key)) { Handle entryMetadataHandle = entryParser.GetUnsigned().AsHandle(); if (entryMetadataHandle.HandleType == HandleType.TypeDefinition) { MetadataReader metadataReader = ModuleList.Instance.GetMetadataReaderForModule(moduleHandle); return(new NamedTypeLookupResult() { MetadataReader = metadataReader, TypeDefinition = entryMetadataHandle.ToTypeDefinitionHandle(metadataReader), RuntimeTypeHandle = key, RuntimeTypeHandleHashcode = hashCode }); } } } } } return(new NamedTypeLookupResult() { RuntimeTypeHandle = key, RuntimeTypeHandleHashcode = hashCode }); }
/// <summary> /// Locate the containing module for a given metadata reader. Assert when not found. /// </summary> /// <param name="reader">Metadata reader to look up</param> /// <returns>Module handle of the module containing the given reader</returns> public static EcmaModuleInfo GetModuleInfoForMetadataReader(this ModuleList moduleList, MetadataReader reader) { foreach (ModuleInfo moduleInfo in moduleList.GetLoadedModuleMapInternal().Modules) { EcmaModuleInfo ecmaModuleInfo = moduleInfo as EcmaModuleInfo; if (ecmaModuleInfo == null) { continue; } if (ecmaModuleInfo.MetadataReader == reader) { return(ecmaModuleInfo); } } // We should never have a reader that is not associated with a module (where does it come from?!) Debug.Assert(false); return(null); }
internal unsafe bool TryGetStaticGenericTypeForComponents(GenericTypeLookupData lookupData, out RuntimeTypeHandle runtimeTypeHandle) { // Search the hashtable for a generic instantiation match // TODO multi-file: consider whether we can limit the search somehow, // i.e. not look at all the modules runtimeTypeHandle = default(RuntimeTypeHandle); NativeHashtable genericsHashtable; ExternalReferencesTable externalReferencesLookup; foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules()) { if (!GetHashtableFromBlob(module, ReflectionMapBlob.GenericsHashtable, out genericsHashtable, out externalReferencesLookup)) { continue; } int lookupHashcode = lookupData.LookupHashCode(); var enumerator = genericsHashtable.Lookup(lookupHashcode); NativeParser entryParser; while (!(entryParser = enumerator.GetNext()).IsNull) { RuntimeTypeHandle tentativeType = externalReferencesLookup.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); if (!lookupData.MatchParsedEntry(tentativeType)) { continue; } runtimeTypeHandle = tentativeType; Debug.Assert(RuntimeAugments.IsGenericType(runtimeTypeHandle)); return(true); } } return(false); }
private static bool TryGetStaticGenericMethodDictionaryForComponents(GenericMethodLookupData lookupData, out IntPtr result) { // Search the hashtable for a generic instantiation match ExternalReferencesTable externalReferencesLookup; NativeHashtable genericMethodsHashtable; foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules()) { if (!GetHashtableFromBlob(module, ReflectionMapBlob.GenericMethodsHashtable, out genericMethodsHashtable, out externalReferencesLookup)) { continue; } int lookupHashcode = lookupData.LookupHashCode(); var enumerator = genericMethodsHashtable.Lookup(lookupHashcode); NativeParser entryParser; while (!(entryParser = enumerator.GetNext()).IsNull) { uint dictionaryIndex = entryParser.GetUnsigned(); if (!lookupData.MatchParsedEntry(ref entryParser, ref externalReferencesLookup, module.Handle)) { continue; } // Current entry matched all inputs, return success result = externalReferencesLookup.GetIntPtrFromIndex(dictionaryIndex); return(true); } } result = IntPtr.Zero; return(false); }
/// <summary> /// Try to look up field access 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 unsafe bool TryGetFieldAccessMetadataFromFieldAccessMap( MetadataReader metadataReader, RuntimeTypeHandle declaringTypeHandle, FieldHandle fieldHandle, CanonicalFormKind canonFormKind, ref FieldAccessMetadata fieldAccessMetadata) { CanonicallyEquivalentEntryLocator canonWrapper = new CanonicallyEquivalentEntryLocator(declaringTypeHandle, canonFormKind); string fieldName = null; RuntimeTypeHandle declaringTypeHandleDefinition = TypeLoaderEnvironment.GetTypeDefinition(declaringTypeHandle); foreach (NativeFormatModuleInfo mappingTableModule in ModuleList.EnumerateModules(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 & FieldTableFlags.IsUniversalCanonicalEntry) != 0)) { continue; } RuntimeTypeHandle entryDeclaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); if (!entryDeclaringTypeHandle.Equals(declaringTypeHandle) && !canonWrapper.IsCanonicallyEquivalent(entryDeclaringTypeHandle)) { continue; } if ((entryFlags & FieldTableFlags.HasMetadataHandle) != 0) { Handle entryFieldHandle = (((int)HandleType.Field << 24) | (int)entryParser.GetUnsigned()).AsHandle(); if (!fieldHandle.Equals(entryFieldHandle)) { continue; } } else { if (fieldName == null) { QTypeDefinition qTypeDefinition; bool success = Instance.TryGetMetadataForNamedType( declaringTypeHandleDefinition, out qTypeDefinition); Debug.Assert(success); MetadataReader nativeFormatMetadataReader = qTypeDefinition.NativeFormatReader; fieldName = nativeFormatMetadataReader.GetString(fieldHandle.GetField(nativeFormatMetadataReader).Name); } string entryFieldName = entryParser.GetString(); if (fieldName != entryFieldName) { continue; } } int fieldOffset; IntPtr fieldAddressCookie = IntPtr.Zero; if (canonFormKind == CanonicalFormKind.Universal) { if (!TypeLoaderEnvironment.Instance.TryGetFieldOffset(declaringTypeHandle, entryParser.GetUnsigned() /* field ordinal */, out fieldOffset)) { Debug.Assert(false); return(false); } } else { if ((entryFlags & FieldTableFlags.FieldOffsetEncodedDirectly) != 0) { fieldOffset = (int)entryParser.GetUnsigned(); } else { fieldOffset = 0; fieldAddressCookie = externalReferences.GetAddressFromIndex(entryParser.GetUnsigned()); FieldTableFlags storageClass = entryFlags & FieldTableFlags.StorageClass; if (storageClass == FieldTableFlags.GCStatic || storageClass == FieldTableFlags.ThreadStatic) { fieldOffset = (int)entryParser.GetUnsigned(); } } } fieldAccessMetadata.MappingTableModule = mappingTableModule.Handle; fieldAccessMetadata.Cookie = fieldAddressCookie; fieldAccessMetadata.Flags = entryFlags; fieldAccessMetadata.Offset = fieldOffset; return(true); } } return(false); }
public TypeLoaderEnvironment() { ModuleList = new ModuleList(); }
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 GVM_RESOLUTION_TRACE Debug.WriteLine("GVM Target Resolution = " + GetTypeNameDebug(targetTypeHandle) + "." + callingMethodNameAndSignature.Name); #endif foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules(RuntimeAugments.GetModuleFromTypeHandle(openTargetTypeHandle))) { NativeReader gvmTableReader; if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.GenericVirtualMethodTable, out gvmTableReader)) { continue; } NativeReader nativeLayoutReader; if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.NativeLayoutInfo, out nativeLayoutReader)) { continue; } NativeParser gvmTableParser = new NativeParser(gvmTableReader, 0); NativeHashtable gvmHashtable = new NativeHashtable(gvmTableParser); ExternalReferencesTable extRefs = default(ExternalReferencesTable); extRefs.InitializeCommonFixupsTable(module); 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 = entryParser.GetUnsigned(); MethodNameAndSignature parsedCallingNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, parsedCallingNameAndSigToken); if (!parsedCallingNameAndSignature.Equals(callingMethodNameAndSignature)) { continue; } uint parsedTargetMethodNameAndSigToken = entryParser.GetUnsigned(); MethodNameAndSignature targetMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, parsedTargetMethodNameAndSigToken); Debug.Assert(targetMethodNameAndSignature != null); if (!TryGetGenericVirtualMethodPointer(targetTypeHandle, targetMethodNameAndSignature, genericArguments, out methodPointer, out dictionaryPointer)) { var sb = new System.Text.StringBuilder(); sb.AppendLine("Generic virtual method pointer lookup failure."); sb.AppendLine(); sb.AppendLine("Declaring type handle: " + declaringType.LowLevelToStringRawEETypeAddress()); sb.AppendLine("Target type handle: " + targetTypeHandle.LowLevelToStringRawEETypeAddress()); sb.AppendLine("Method name: " + targetMethodNameAndSignature.Name); sb.AppendLine("Instantiation:"); for (int i = 0; i < genericArguments.Length; i++) { sb.AppendLine(" Argument " + i.LowLevelToString() + ": " + genericArguments[i].LowLevelToStringRawEETypeAddress()); } Environment.FailFast(sb.ToString()); } return(true); } } return(false); }
/// <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 unsafe static 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); }
private static InstantiatedMethod TryGetGenericMethodTemplate_Internal(InstantiatedMethod concreteMethod, CanonicalFormKind kind, out NativeFormatModuleInfo nativeLayoutInfoModule, out uint nativeLayoutInfoToken) { nativeLayoutInfoModule = null; nativeLayoutInfoToken = 0; var canonForm = concreteMethod.GetCanonMethodTarget(kind); var hashCode = canonForm.GetHashCode(); foreach (NativeFormatModuleInfo moduleInfo in ModuleList.EnumerateModules()) { NativeReader nativeLayoutReader = TypeLoaderEnvironment.GetNativeLayoutInfoReader(moduleInfo.Handle); if (nativeLayoutReader == null) { continue; } NativeHashtable genericMethodTemplatesHashtable = LoadHashtable(moduleInfo, ReflectionMapBlob.GenericMethodsTemplateMap, out _); if (genericMethodTemplatesHashtable.IsNull) { continue; } var context = new NativeLayoutInfoLoadContext { _typeSystemContext = concreteMethod.Context, _typeArgumentHandles = concreteMethod.OwningType.Instantiation, _methodArgumentHandles = concreteMethod.Instantiation, _module = moduleInfo }; var enumerator = genericMethodTemplatesHashtable.Lookup(hashCode); NativeParser entryParser; while (!(entryParser = enumerator.GetNext()).IsNull) { var methodSignatureParser = new NativeParser(nativeLayoutReader, entryParser.GetUnsigned()); // Get the unified generic method holder and convert it to its canonical form var candidateTemplate = (InstantiatedMethod)context.GetMethod(ref methodSignatureParser); Debug.Assert(candidateTemplate.Instantiation.Length > 0); if (canonForm == candidateTemplate.GetCanonMethodTarget(kind)) { TypeLoaderLogger.WriteLine("Found template for generic method " + concreteMethod.ToString() + ": " + candidateTemplate.ToString()); nativeLayoutInfoModule = moduleInfo; nativeLayoutInfoToken = entryParser.GetUnsigned(); if (nativeLayoutInfoToken == BadTokenFixupValue) { // TODO: once multifile gets fixed up, make this throw a BadImageFormatException TypeLoaderLogger.WriteLine("ERROR: template not fixed up, skipping"); continue; } Debug.Assert( (kind != CanonicalFormKind.Universal) || (kind == CanonicalFormKind.Universal && candidateTemplate == candidateTemplate.GetCanonMethodTarget(kind))); return(candidateTemplate); } } } TypeLoaderLogger.WriteLine("ERROR: Cannot find a suitable template for generic method " + concreteMethod.ToString()); return(null); }
/// <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; 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 (NativeFormatModuleInfo mappingTableModule in ModuleList.EnumerateModules(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(); FieldTableFlags storageClass = entryFlags & FieldTableFlags.StorageClass; Debug.Assert((entryFlags & FieldTableFlags.IsUniversalCanonicalEntry) == 0); if (storageClass == FieldTableFlags.Instance) { continue; } switch (fieldAccessKind) { case FieldAccessStaticDataKind.NonGC: if (storageClass != FieldTableFlags.NonGCStatic) { continue; } break; case FieldAccessStaticDataKind.GC: if (storageClass != FieldTableFlags.GCStatic) { continue; } break; case FieldAccessStaticDataKind.TLS: if (storageClass != FieldTableFlags.ThreadStatic) { continue; } break; default: return(false); } RuntimeTypeHandle entryDeclaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); if (!entryDeclaringTypeHandle.Equals(declaringTypeHandle)) { continue; } if ((entryFlags & FieldTableFlags.HasMetadataHandle) != 0) { // skip metadata handle entryParser.GetUnsigned(); } else { // skip field name entryParser.SkipString(); } IntPtr fieldAddress = IntPtr.Zero; if ((entryFlags & FieldTableFlags.FieldOffsetEncodedDirectly) == 0) { fieldAddress = externalReferences.GetAddressFromIndex(entryParser.GetUnsigned()); } if (fieldAddress != IntPtr.Zero) { staticsRegionAddress = fieldAddress; break; } } // Static fields for a type can only be found in at most one module if (staticsRegionAddress != IntPtr.Zero) { break; } } return(staticsRegionAddress != IntPtr.Zero); }
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 (NativeFormatModuleInfo module in ModuleList.EnumerateModules(RuntimeAugments.GetModuleFromTypeHandle(openTargetTypeHandle))) { NativeReader gvmTableReader; if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.GenericVirtualMethodTable, out gvmTableReader)) { continue; } NativeReader nativeLayoutReader; if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.NativeLayoutInfo, out nativeLayoutReader)) { continue; } NativeParser gvmTableParser = new NativeParser(gvmTableReader, 0); NativeHashtable gvmHashtable = new NativeHashtable(gvmTableParser); ExternalReferencesTable extRefs = default(ExternalReferencesTable); extRefs.InitializeCommonFixupsTable(module); 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.GetExternalNativeLayoutOffset(entryParser.GetUnsigned()); MethodNameAndSignature parsedCallingNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, parsedCallingNameAndSigToken); if (!parsedCallingNameAndSignature.Equals(callingMethodNameAndSignature)) { continue; } uint parsedTargetMethodNameAndSigToken = extRefs.GetExternalNativeLayoutOffset(entryParser.GetUnsigned()); MethodNameAndSignature targetMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, parsedTargetMethodNameAndSigToken); Debug.Assert(targetMethodNameAndSignature != null); if (!TryGetGenericVirtualMethodPointer(targetTypeHandle, targetMethodNameAndSignature, genericArguments, out methodPointer, out dictionaryPointer)) { Environment.FailFast("GVM method pointer lookup failure"); } return(true); } } 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 (NativeFormatModuleInfo module in ModuleList.EnumerateModules(RuntimeAugments.GetModuleFromTypeHandle(openTargetTypeHandle))) { NativeReader gvmTableReader; if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.InterfaceGenericVirtualMethodTable, out gvmTableReader)) { continue; } NativeReader nativeLayoutReader; if (!TryGetNativeReaderForBlob(module, ReflectionMapBlob.NativeLayoutInfo, out nativeLayoutReader)) { continue; } NativeParser gvmTableParser = new NativeParser(gvmTableReader, 0); NativeHashtable gvmHashtable = new NativeHashtable(gvmTableParser); ExternalReferencesTable extRefs = default(ExternalReferencesTable); extRefs.InitializeCommonFixupsTable(module); 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.GetExternalNativeLayoutOffset(entryParser.GetUnsigned()); MethodNameAndSignature interfaceMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, 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(module, 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(module, nativeLayoutReader, ref entryParser, ref extRefs, ref declaringType, ref methodNameAndSignature, openTargetTypeHandle, targetTypeInstantiation, true)) { return(true); } } } return(false); }