private void AddToFieldLayout(int offset, TypeDesc fieldType) { if (fieldType.IsGCPointer) { if (offset % _pointerSize != 0) { // Misaligned ORef ThrowFieldLayoutError(offset); } SetFieldLayout(offset, _pointerSize, FieldLayoutTag.ORef); } else if (fieldType.IsPointer || fieldType.IsFunctionPointer) { SetFieldLayout(offset, _pointerSize, FieldLayoutTag.NonORef); } else if (fieldType.IsValueType) { if (fieldType.IsByRefLike && offset % _pointerSize != 0) { // Misaligned ByRefLike ThrowFieldLayoutError(offset); } MetadataType mdType = (MetadataType)fieldType; int fieldSize = mdType.InstanceByteCountUnaligned.AsInt; if (!mdType.ContainsGCPointers) { // Plain value type, mark the entire range as NonORef SetFieldLayout(offset, fieldSize, FieldLayoutTag.NonORef); } else { if (offset % _pointerSize != 0) { // Misaligned struct with GC pointers ThrowFieldLayoutError(offset); } bool[] fieldORefMap = new bool[fieldSize]; MarkORefLocations(mdType, fieldORefMap, offset: 0); for (int index = 0; index < fieldSize; index++) { SetFieldLayout(offset + index, fieldORefMap[index] ? FieldLayoutTag.ORef : FieldLayoutTag.NonORef); } } } else if (fieldType.IsByRef) { if (offset % _pointerSize != 0) { // Misaligned pointer field ThrowFieldLayoutError(offset); } SetFieldLayout(offset, _pointerSize, FieldLayoutTag.NonORef); } else { Debug.Assert(false, fieldType.ToString()); } }
/// <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; }
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; }
/// <summary> /// Locate field on native format type and fill in the field access flags and offset. /// </summary> /// <param name="type">Metadata reader for the declaring type</param> /// <param name="fieldName">Field name</param> /// <param name="fieldAccessMetadata">Output - metadata information for field accessor construction</param> /// <returns>true when found, false otherwise</returns> private static bool TryGetFieldAccessMetadataForNativeFormatType( TypeDesc type, string fieldName, ref FieldAccessMetadata fieldAccessMetadata) { #if SUPPORTS_NATIVE_METADATA_TYPE_LOADING FieldDesc fieldDesc = type.GetField(fieldName); if (fieldDesc == null) { return false; } fieldAccessMetadata.MappingTableModule = IntPtr.Zero; #if SUPPORTS_R2R_LOADING fieldAccessMetadata.MappingTableModule = ModuleList.Instance.GetModuleForMetadataReader(((NativeFormatType)type.GetTypeDefinition()).MetadataReader); #endif fieldAccessMetadata.Offset = fieldDesc.Offset; fieldAccessMetadata.Flags = FieldTableFlags.HasMetadataHandle; if (fieldDesc.IsThreadStatic) { // Specify that the data is thread local fieldAccessMetadata.Flags |= FieldTableFlags.ThreadStatic; // Specify that the general purpose field access routine that only relies on offset should be used. fieldAccessMetadata.Flags |= FieldTableFlags.IsUniversalCanonicalEntry; } else if (fieldDesc.IsStatic) { uint nonGcStaticsRVA = 0; uint gcStaticsRVA = 0; bool nonGenericCase = false; if (type is MetadataType) { // Static fields on Non-Generic types are contained within the module, and their offsets // are adjusted by their static rva base. nonGenericCase = true; #if SUPPORTS_R2R_LOADING if (!TryGetStaticsTableEntry((MetadataType)type, nonGcStaticsRVA: out nonGcStaticsRVA, gcStaticsRVA: out gcStaticsRVA)) #endif { Environment.FailFast( "Failed to locate statics table entry for for field '" + fieldName + "' on type " + type.ToString()); } } if (fieldDesc.HasGCStaticBase) { if ((gcStaticsRVA == 0) && nonGenericCase) { Environment.FailFast( "GC statics region was not found for field '" + fieldName + "' on type " + type.ToString()); } fieldAccessMetadata.Offset += (int)gcStaticsRVA; fieldAccessMetadata.Flags |= FieldTableFlags.IsGcSection; } else { if ((nonGcStaticsRVA == 0) && nonGenericCase) { Environment.FailFast( "Non-GC statics region was not found for field '" + fieldName + "' on type " + type.ToString()); } fieldAccessMetadata.Offset += (int)nonGcStaticsRVA; } fieldAccessMetadata.Flags |= FieldTableFlags.Static; return true; } else { // Instance field fieldAccessMetadata.Flags |= FieldTableFlags.Instance; } return true; #else return false; #endif }
private void AddToFieldLayout(int offset, TypeDesc fieldType) { if (fieldType.IsGCPointer) { if (offset % _pointerSize != 0) { // Misaligned ORef ThrowFieldLayoutError(offset); } SetFieldLayout(offset, _pointerSize, FieldLayoutTag.ORef); } else if (fieldType.IsPointer || fieldType.IsFunctionPointer) { SetFieldLayout(offset, _pointerSize, FieldLayoutTag.NonORef); } else if (fieldType.IsValueType) { MetadataType mdType = (MetadataType)fieldType; int fieldSize = mdType.InstanceByteCountUnaligned.AsInt; if (!mdType.ContainsGCPointers && !mdType.IsByRefLike) { // Plain value type, mark the entire range as NonORef SetFieldLayout(offset, fieldSize, FieldLayoutTag.NonORef); } else { if (offset % _pointerSize != 0) { // Misaligned struct with GC pointers or ByRef ThrowFieldLayoutError(offset); } List <FieldLayoutInterval> fieldRefMap = new(); MarkByRefAndORefLocations(mdType, fieldRefMap, offset: 0); // Merge in fieldRefMap from structure specifying not attributed intervals as NonORef int lastGCRegionReportedEnd = 0; foreach (var gcRegion in fieldRefMap) { SetFieldLayout(offset + lastGCRegionReportedEnd, gcRegion.Start - lastGCRegionReportedEnd, FieldLayoutTag.NonORef); Debug.Assert(gcRegion.Tag == FieldLayoutTag.ORef || gcRegion.Tag == FieldLayoutTag.ByRef); SetFieldLayout(offset + gcRegion.Start, gcRegion.Size, gcRegion.Tag); lastGCRegionReportedEnd = gcRegion.EndSentinel; } if (fieldRefMap.Count > 0) { int trailingRegionStart = fieldRefMap[fieldRefMap.Count - 1].EndSentinel; int trailingRegionSize = fieldSize - trailingRegionStart; SetFieldLayout(offset + trailingRegionStart, trailingRegionSize, FieldLayoutTag.NonORef); } } } else if (fieldType.IsByRef) { if (offset % _pointerSize != 0) { // Misaligned pointer field ThrowFieldLayoutError(offset); } SetFieldLayout(offset, _pointerSize, FieldLayoutTag.ByRef); } else { Debug.Assert(false, fieldType.ToString()); } }
// The layout algorithm should probably compute results and let the caller set things internal unsafe int[] ComputeTypeSizeAndAlignment(TypeDesc type, FieldLoadState loadRequested, out LowLevelList<int> fieldOffsets) { fieldOffsets = null; TypeLoaderLogger.WriteLine("Laying out type " + type.ToString() + ". IsValueType: " + (type.IsValueType ? "true" : "false") + ". LoadRequested = " + ((int)loadRequested).LowLevelToString()); Debug.Assert(loadRequested != FieldLoadState.None); Debug.Assert(type is ArrayType || (type is DefType && ((DefType)type).HasInstantiation)); bool isArray = type is ArrayType; int[] position = new int[5]; int alignRequired = 1; if ((loadRequested & FieldLoadState.Instance) == FieldLoadState.Instance) { ComputeTypeSizeBeforeFields(type, out position[(int)NativeFormat.FieldStorage.Instance], out alignRequired); } if (!isArray) { // Once this is done, the NativeLayoutFields on the type are initialized EnsureFieldLayoutLoadedForGenericType((DefType)type); Debug.Assert(type.NativeLayoutFields != null); } int instanceFields = 0; if (!isArray && type.NativeLayoutFields.Length > 0) { fieldOffsets = new LowLevelList<int>(type.NativeLayoutFields.Length); for (int i = 0; i < type.NativeLayoutFields.Length; i++) { TypeDesc fieldType = type.NativeLayoutFields[i].FieldType; int fieldStorage = (int)type.NativeLayoutFields[i].FieldStorage; if (!ShouldProcessField((NativeFormat.FieldStorage)fieldStorage, loadRequested)) continue; // For value types, we will attempt to get the size and alignment from // the runtime if possible, otherwise GetFieldSizeAndAlignment will // recurse to lay out nested struct fields. int alignment; int size; GetFieldSizeAlignment(fieldType, out size, out alignment); Debug.Assert(alignment > 0); if (fieldStorage == (int)NativeFormat.FieldStorage.Instance) { instanceFields++; // Ensure alignment of type is sufficient for this field if (alignRequired < alignment) alignRequired = alignment; } position[fieldStorage] = MemoryHelpers.AlignUp(position[fieldStorage], alignment); TypeLoaderLogger.WriteLine(" --> Field type " + fieldType.ToString() + " storage " + ((uint)(type.NativeLayoutFields[i].FieldStorage)).LowLevelToString() + " offset " + position[fieldStorage].LowLevelToString() + " alignment " + alignment.LowLevelToString()); fieldOffsets.Add(position[fieldStorage]); position[fieldStorage] += size; } } // Pad the length of structs to be 1 if they are empty so we have no zero-length structures if ((position[(int)NativeFormat.FieldStorage.Instance] == 0) && type.IsValueType) position[(int)NativeFormat.FieldStorage.Instance] = 1; Debug.Assert(alignRequired == 1 || alignRequired == 2 || alignRequired == 4 || alignRequired == 8); position[InstanceAlignmentEntry] = alignRequired; return position; }
public override DefType[] ComputeRuntimeInterfaces(TypeDesc type) { TypeBuilderState state = type.GetOrCreateTypeBuilderState(); int totalInterfaces = RuntimeAugments.GetInterfaceCount(state.TemplateType.RuntimeTypeHandle); TypeLoaderLogger.WriteLine("Building runtime interfaces for type " + type.ToString() + " (total interfaces = " + totalInterfaces.LowLevelToString() + ") ..."); DefType[] interfaces = new DefType[totalInterfaces]; int numInterfaces = 0; // // Copy over all interfaces from base class // if (type.BaseType != null) { foreach (var baseInterface in type.BaseType.RuntimeInterfaces) { // There should be no duplicates Debug.Assert(!InterfaceInSet(interfaces, numInterfaces, baseInterface)); interfaces[numInterfaces++] = baseInterface; TypeLoaderLogger.WriteLine(" -> Added basetype interface " + baseInterface.ToString() + " on type " + type.ToString()); } } NativeParser typeInfoParser = state.GetParserForNativeLayoutInfo(); NativeParser interfaceParser = typeInfoParser.GetParserForBagElementKind(BagElementKind.ImplementedInterfaces); TypeDesc[] implementedInterfaces; if (!interfaceParser.IsNull) implementedInterfaces = state.NativeLayoutInfo.LoadContext.GetTypeSequence(ref interfaceParser); else implementedInterfaces = TypeDesc.EmptyTypes; // Note that the order in which the interfaces are added to the list is same as the order in which the MDIL binder adds them. // It is required for correctness foreach (TypeDesc interfaceType in implementedInterfaces) { DefType interfaceTypeAsDefType = (DefType)interfaceType; // Skip duplicates if (InterfaceInSet(interfaces, numInterfaces, interfaceTypeAsDefType)) continue; interfaces[numInterfaces++] = interfaceTypeAsDefType; TypeLoaderLogger.WriteLine(" -> Added interface " + interfaceTypeAsDefType.ToString() + " on type " + type.ToString()); foreach (var inheritedInterface in interfaceTypeAsDefType.RuntimeInterfaces) { // Skip duplicates if (InterfaceInSet(interfaces, numInterfaces, inheritedInterface)) continue; interfaces[numInterfaces++] = inheritedInterface; TypeLoaderLogger.WriteLine(" -> Added inherited interface " + inheritedInterface.ToString() + " on type " + type.ToString()); } } // TODO: Handle the screwy cases of generic interface folding Debug.Assert(numInterfaces == totalInterfaces, "Unexpected number of interfaces"); return interfaces; }