/// <summary> /// Helper API to convert a type to its canonical or universal canonical form. /// Note that for now, there is no mixture between specific canonical and universal canonical forms, /// meaning that the canonical form or Foo<string, int> can either be Foo<__Canon, int> or /// Foo<__UniversalCanon, __UniversalCanon>. It cannot be Foo<__Canon, __UniversalCanon> (yet) /// for simplicity. We can always change that rule in the futue and add support for the mixture, but /// for now we are keeping it simple. /// </summary> public static TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) { TypeSystemContext context = typeToConvert.Context; if (kind == CanonicalFormKind.Universal) { return(context.UniversalCanonType); } else if (kind == CanonicalFormKind.Specific) { if (typeToConvert == context.UniversalCanonType) { return(context.UniversalCanonType); } else if (typeToConvert.IsSignatureVariable) { return(typeToConvert); } else if (typeToConvert.IsDefType) { if (!typeToConvert.IsValueType) { return(context.CanonType); } else if (typeToConvert.HasInstantiation) { return(typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific)); } else { return(typeToConvert); } } else if (typeToConvert.IsArray) { return(context.CanonType); } else { return(typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific)); } } else { Debug.Assert(false); return(null); } }
/// <summary> /// Get the NativeLayout for a type from a ReadyToRun image. /// </summary> public bool TryGetMetadataNativeLayout(TypeDesc concreteType, out IntPtr nativeLayoutInfoModule, out uint nativeLayoutInfoToken) { nativeLayoutInfoModule = default(IntPtr); 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(); var loadedModulesCount = RuntimeAugments.GetLoadedModules(null); var loadedModuleHandles = new IntPtr[loadedModulesCount]; var loadedModules = RuntimeAugments.GetLoadedModules(loadedModuleHandles); Debug.Assert(loadedModulesCount == loadedModules); #if SUPPORTS_R2R_LOADING foreach (var moduleHandle in loadedModuleHandles) { ExternalReferencesTable externalFixupsTable; NativeHashtable typeTemplatesHashtable = LoadHashtable(moduleHandle, ReflectionMapBlob.MetadataBasedTypeTemplateMap, out externalFixupsTable); if (typeTemplatesHashtable.IsNull) continue; var enumerator = typeTemplatesHashtable.Lookup(hashCode); var nativeMetadataUnit = nativeMetadataType.Context.ResolveMetadataUnit(moduleHandle); 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 = (uint)externalFixupsTable.GetRvaFromIndex(entryParser.GetUnsigned()); if (nativeLayoutInfoToken == BadTokenFixupValue) { throw new BadImageFormatException(); } nativeLayoutInfoModule = moduleHandle; return true; } } } #endif #endif return false; }
/// <summary> /// Helper API to convert a type to its canonical or universal canonical form. /// Note that for now, there is no mixture between specific canonical and universal canonical forms, /// meaning that the canonical form or Foo<string, int> can either be Foo<__Canon, int> or /// Foo<__UniversalCanon, __UniversalCanon>. It cannot be Foo<__Canon, __UniversalCanon> (yet) /// for simplicity. We can always change that rule in the futue and add support for the mixture, but /// for now we are keeping it simple. /// </summary> public static TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) { TypeSystemContext context = typeToConvert.Context; if (kind == CanonicalFormKind.Universal) { return context.UniversalCanonType; } else if (kind == CanonicalFormKind.Specific) { if (typeToConvert == context.UniversalCanonType) { return context.UniversalCanonType; } else if (typeToConvert.IsDefType) { if (!typeToConvert.IsValueType) return context.CanonType; else if (typeToConvert.HasInstantiation) return typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); else return typeToConvert; } else if (typeToConvert.IsArray) { return context.CanonType; } else { return typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); } } else { Debug.Assert(false); return null; } }
public static TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) { TypeSystemContext context = typeToConvert.Context; if (kind == CanonicalFormKind.Universal) { return(context.UniversalCanonType); } else if (kind == CanonicalFormKind.Specific) { if (typeToConvert == context.UniversalCanonType) { kind = CanonicalFormKind.Universal; return(context.UniversalCanonType); } else if (typeToConvert.IsSignatureVariable) { return(typeToConvert); } else if (typeToConvert.IsDefType) { if (!typeToConvert.IsValueType) { return(context.CanonType); } else if (typeToConvert.HasInstantiation) { // This is a generic struct type. If the generic struct is instantiated over universal canon, // the entire struct becomes universally canonical. if (typeToConvert.IsCanonicalSubtype(CanonicalFormKind.Universal)) { kind = CanonicalFormKind.Universal; return(context.UniversalCanonType); } TypeDesc canonicalType = typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); // We could still have ended up with a universal canonical form here because conversion to // canon form strips runtime determined types from their constituents. // MyStruct<T__UniversalCanon> (which is not universally canonical) becomes MyStruct<__UniversalCanon>. if (canonicalType.IsCanonicalSubtype(CanonicalFormKind.Universal)) { kind = CanonicalFormKind.Universal; return(context.UniversalCanonType); } return(canonicalType); } else if (typeToConvert.IsRuntimeDeterminedType) { // For non-universal canon cases, RuntimeDeterminedType's passed into this function are either // reference types (which are turned into normal Canon), or instantiated types (which are handled // by the above case.). But for UniversalCanon, we can have non-instantiated universal canon // which will reach this case. // We should only ever reach this for T__UniversalCanon. Debug.Assert(((RuntimeDeterminedType)typeToConvert).CanonicalType == context.UniversalCanonType); kind = CanonicalFormKind.Universal; return(context.UniversalCanonType); } else { return(typeToConvert); } } else if (typeToConvert.IsArray) { return(context.CanonType); } else { if (typeToConvert.IsCanonicalSubtype(CanonicalFormKind.Universal)) { kind = CanonicalFormKind.Universal; return(context.UniversalCanonType); } return(typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific)); } } else { Debug.Assert(false); return(null); } }
public static TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) { TypeSystemContext context = typeToConvert.Context; if (kind == CanonicalFormKind.Universal) { return context.UniversalCanonType; } else if (kind == CanonicalFormKind.Specific) { if (typeToConvert == context.UniversalCanonType) { kind = CanonicalFormKind.Universal; return context.UniversalCanonType; } else if (typeToConvert.IsSignatureVariable) { return typeToConvert; } else if (typeToConvert.IsDefType) { if (!typeToConvert.IsValueType) { return context.CanonType; } else if (typeToConvert.HasInstantiation) { TypeDesc canonicalType = typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); // This is a generic struct type. If the generic struct is instantiated over universal canon, // the entire struct becomes universally canonical. if (canonicalType.IsCanonicalSubtype(CanonicalFormKind.Universal)) { kind = CanonicalFormKind.Universal; return context.UniversalCanonType; } return canonicalType; } else if (typeToConvert.IsRuntimeDeterminedType) { // For non-universal canon cases, RuntimeDeterminedType's passed into this function are either // reference types (which are turned into normal Canon), or instantiated types (which are handled // by the above case.). But for UniversalCanon, we can have non-instantiated universal canon // which will reach this case. // We should only ever reach this for T__UniversalCanon. Debug.Assert(((RuntimeDeterminedType)typeToConvert).CanonicalType == context.UniversalCanonType); kind = CanonicalFormKind.Universal; return context.UniversalCanonType; } else { return typeToConvert; } } else if (typeToConvert.IsArray) { return context.CanonType; } else { if (typeToConvert.IsCanonicalSubtype(CanonicalFormKind.Universal)) { kind = CanonicalFormKind.Universal; return context.UniversalCanonType; } return typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); } } else { Debug.Assert(false); return null; } }
private TypeDesc TryGetTypeTemplate_Internal(TypeDesc concreteType, CanonicalFormKind kind, out IntPtr nativeLayoutInfoModule, out uint nativeLayoutInfoToken) { nativeLayoutInfoModule = default(IntPtr); nativeLayoutInfoToken = 0; var canonForm = concreteType.ConvertToCanonForm(kind); var hashCode = canonForm.GetHashCode(); var loadedModulesCount = RuntimeAugments.GetLoadedModules(null); var loadedModuleHandles = new IntPtr[loadedModulesCount]; var loadedModules = RuntimeAugments.GetLoadedModules(loadedModuleHandles); Debug.Assert(loadedModulesCount == loadedModules); foreach (var moduleHandle in loadedModuleHandles) { ExternalReferencesTable externalFixupsTable; NativeHashtable typeTemplatesHashtable = LoadHashtable(moduleHandle, 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 = (uint)externalFixupsTable.GetRvaFromIndex(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 && candidateTemplate != candidateTemplate.ConvertToCanonForm(kind)) || (kind == CanonicalFormKind.Universal && candidateTemplate == candidateTemplate.ConvertToCanonForm(kind))); nativeLayoutInfoModule = moduleHandle; return candidateTemplate; } } } TypeLoaderLogger.WriteLine("ERROR: Cannot find a suitable template for type " + concreteType.ToString()); return null; }
private static TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) { TypeSystemContext context = typeToConvert.Context; if (kind == CanonicalFormKind.Universal) { return context.UniversalCanonType; } else if (kind == CanonicalFormKind.Specific) { if (typeToConvert == context.UniversalCanonType) { kind = CanonicalFormKind.Universal; return context.UniversalCanonType; } else if (typeToConvert.IsSignatureVariable) { return typeToConvert; } else if (typeToConvert.IsDefType) { if (!typeToConvert.IsValueType) return context.CanonType; else if (typeToConvert.HasInstantiation) { TypeDesc convertedType = typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); if (convertedType.IsCanonicalSubtype(CanonicalFormKind.Universal)) { kind = CanonicalFormKind.Universal; return context.UniversalCanonType; } return convertedType; } else return typeToConvert; } else if (typeToConvert.IsArray) { return context.CanonType; } else { TypeDesc convertedType = typeToConvert.ConvertToCanonForm(CanonicalFormKind.Specific); if (convertedType.IsCanonicalSubtype(CanonicalFormKind.Universal)) { kind = CanonicalFormKind.Universal; return context.UniversalCanonType; } return convertedType; } } else { Debug.Assert(false); return null; } }