Пример #1
0
        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());
            }
        }
Пример #2
0
        /// <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;
        }
Пример #3
0
        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
        }
Пример #5
0
        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());
            }
        }
Пример #6
0
        // 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;
        }