Ejemplo n.º 1
0
        private static void EnsureFieldLayoutLoadedForNonUniversalType(DefType type)
        {
            Debug.Assert(type.HasInstantiation);
            Debug.Assert(!type.ComputeTemplate().IsCanonicalSubtype(CanonicalFormKind.Universal));

            if (type.NativeLayoutFields != null)
            {
                return;
            }

            // Look up the universal template for this type.  Only the universal template has field layout
            // information, so we have to use it to parse the field layout.
            NativeLayoutInfoLoadContext universalLayoutLoadContext;
            NativeLayoutInfo            universalLayoutInfo;
            NativeParser typeInfoParser = type.GetOrCreateTypeBuilderState().GetParserForUniversalNativeLayoutInfo(out universalLayoutLoadContext, out universalLayoutInfo);

            if (typeInfoParser.IsNull)
            {
                throw new TypeBuilder.MissingTemplateException();
            }

            // Now parse that layout into the NativeLayoutFields array.
            NativeParser fieldLayoutParser = typeInfoParser.GetParserForBagElementKind(BagElementKind.FieldLayout);

            type.NativeLayoutFields = ParseFieldLayout(type, universalLayoutLoadContext, fieldLayoutParser);
        }
        public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind)
        {
            if (!type.IsTemplateUniversal() && (layoutKind == InstanceLayoutKind.TypeOnly))
            {
                // Non universal generics can just use the template's layout
                DefType template = (DefType)type.ComputeTemplate();
                return(_noMetadataFieldLayoutAlgorithm.ComputeInstanceLayout(template, InstanceLayoutKind.TypeOnly));
            }

            // Only needed for universal generics, or when looking up an offset for a field for a universal generic
            LowLevelList <int> fieldOffsets;

            int[] position = ComputeTypeSizeAndAlignment(type, FieldLoadState.Instance, out fieldOffsets);

            int numInstanceFields = 0;

            foreach (NativeLayoutFieldDesc field in type.NativeLayoutFields)
            {
                if (!field.IsStatic)
                {
                    numInstanceFields++;
                }
            }

            int byteCountAlignment = position[InstanceAlignmentEntry];

            byteCountAlignment = type.Context.Target.GetObjectAlignment(byteCountAlignment);

            ComputedInstanceFieldLayout layout = new ComputedInstanceFieldLayout()
            {
                Offsets            = new FieldAndOffset[numInstanceFields],
                ByteCountAlignment = byteCountAlignment,
                ByteCountUnaligned = position[(int)NativeFormat.FieldStorage.Instance],
                PackValue          = 0 // TODO, as we add more metadata handling logic, find out if its necessary to use a meaningful value here
            };

            if (!type.IsValueType)
            {
                layout.FieldAlignment = type.Context.Target.PointerSize;
                layout.FieldSize      = type.Context.Target.PointerSize;
            }
            else
            {
                layout.FieldAlignment = position[InstanceAlignmentEntry];
                layout.FieldSize      = MemoryHelpers.AlignUp(position[(int)NativeFormat.FieldStorage.Instance], layout.FieldAlignment);
            }

            int curInstanceField = 0;

            foreach (NativeLayoutFieldDesc field in type.NativeLayoutFields)
            {
                if (!field.IsStatic)
                {
                    layout.Offsets[curInstanceField] = new FieldAndOffset(field, fieldOffsets[curInstanceField]);
                    curInstanceField++;
                }
            }

            return(layout);
        }
Ejemplo n.º 3
0
        public unsafe override bool ComputeIsByRefLike(DefType type)
        {
            if (type.RetrieveRuntimeTypeHandleIfPossible())
            {
                return(type.RuntimeTypeHandle.ToEETypePtr()->IsByRefLike);
            }

            // Being ByRefLike is a property of the uninstantiated form of a type (so its set on all kinds of templates reliably)
            return(type.ComputeTemplate().RuntimeTypeHandle.ToEETypePtr()->IsByRefLike);
        }
Ejemplo n.º 4
0
        private static void EnsureFieldLayoutLoadedForUniversalType(DefType type, NativeLayoutInfoLoadContext loadContext, NativeParser fieldLayoutParser)
        {
            Debug.Assert(type.HasInstantiation);
            Debug.Assert(type.ComputeTemplate().IsCanonicalSubtype(CanonicalFormKind.Universal));

            if (type.NativeLayoutFields != null)
            {
                return;
            }

            type.NativeLayoutFields = ParseFieldLayout(type, loadContext, fieldLayoutParser);
        }
Ejemplo n.º 5
0
        public unsafe override bool ComputeContainsGCPointers(DefType type)
        {
            if (type.IsTemplateCanonical())
            {
                return(type.ComputeTemplate().RuntimeTypeHandle.ToEETypePtr()->HasGCPointers);
            }
            else
            {
                if (type.RetrieveRuntimeTypeHandleIfPossible())
                {
                    return(type.RuntimeTypeHandle.ToEETypePtr()->HasGCPointers);
                }

                return(type.GetOrCreateTypeBuilderState().InstanceGCLayout != null);
            }
        }
Ejemplo n.º 6
0
        public unsafe override bool ComputeIsByRefLike(DefType type)
        {
            if (type.IsTemplateCanonical())
            {
                return(type.ComputeTemplate().RuntimeTypeHandle.ToEETypePtr()->IsByRefLike);
            }
            else
            {
                if (type.RetrieveRuntimeTypeHandleIfPossible())
                {
                    return(type.RuntimeTypeHandle.ToEETypePtr()->IsByRefLike);
                }

                throw new NotImplementedException();
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Get an enumerable list of the fields used for dynamic gc layout calculation.
        /// </summary>
        private IEnumerable <FieldDesc> GetFieldsForGCLayout()
        {
            DefType defType = (DefType)TypeBeingBuilt;

            IEnumerable <FieldDesc> fields;

            if (defType.ComputeTemplate(false) != null)
            {
                // we have native layout and a template. Use the NativeLayoutFields as that is the only complete
                // description of the fields available. (There may be metadata fields, but those aren't guaranteed
                // to be a complete set of fields due to reflection reduction.
                NativeLayoutFieldAlgorithm.EnsureFieldLayoutLoadedForGenericType(defType);
                fields = defType.NativeLayoutFields;
            }
            else
            {
                // The metadata case. We're loading the type from regular metadata, so use the regular metadata fields
                fields = defType.GetFields();
            }

            return(fields);
        }
Ejemplo n.º 8
0
        public unsafe override DefType ComputeHomogeneousFloatAggregateElementType(DefType type)
        {
            if (type.Context.Target.Architecture == TargetArchitecture.ARM)
            {
                if (!type.IsValueType)
                {
                    return(null);
                }

                // There is no reason to compute the entire field layout for the HFA type/flag if
                // the template type is not a universal generic type (information stored in rare flags on the EEType)
                TypeDesc templateType = type.ComputeTemplate(false);
                if (templateType != null && !templateType.IsCanonicalSubtype(CanonicalFormKind.Universal))
                {
                    EEType *pEETemplate = templateType.GetRuntimeTypeHandle().ToEETypePtr();
                    if (!pEETemplate->IsHFA)
                    {
                        return(null);
                    }

                    if (pEETemplate->RequiresAlign8)
                    {
                        return(type.Context.GetWellKnownType(WellKnownType.Double));
                    }
                    else
                    {
                        return(type.Context.GetWellKnownType(WellKnownType.Single));
                    }
                }

                // Once this is done, the NativeLayoutFields on the type are initialized
                EnsureFieldLayoutLoadedForGenericType((DefType)type);
                Debug.Assert(type.NativeLayoutFields != null);

                // Empty types are not HFA
                if (type.NativeLayoutFields.Length == 0)
                {
                    return(null);
                }

                DefType currentHfaElementType = null;

                for (int i = 0; i < type.NativeLayoutFields.Length; i++)
                {
                    TypeDesc fieldType = type.NativeLayoutFields[i].FieldType;
                    if (type.NativeLayoutFields[i].FieldStorage != NativeFormat.FieldStorage.Instance)
                    {
                        continue;
                    }

                    DefType fieldDefType = fieldType as DefType;

                    // HFA types cannot contain non-HFA types
                    if (fieldDefType == null || !fieldDefType.IsHfa)
                    {
                        return(null);
                    }

                    Debug.Assert(fieldDefType.HfaElementType != null);

                    if (currentHfaElementType == null)
                    {
                        currentHfaElementType = fieldDefType.HfaElementType;
                    }
                    else if (currentHfaElementType != fieldDefType.HfaElementType)
                    {
                        return(null); // If the field doesn't have the same HFA type as the one we've looked at before, the type cannot be HFA
                    }
                }

                // If we didn't find any instance fields, then this can't be an HFA type
                if (currentHfaElementType == null)
                {
                    return(null);
                }

                // Note that we check the total size, but do not perform any checks on number of fields:
                // - Type of fields can be HFA valuetype itself
                // - Managed C++ HFA valuetypes have just one <alignment member> of type float to signal that
                //   the valuetype is HFA and explicitly specified size
                int maxSize = currentHfaElementType.InstanceFieldSize.AsInt * currentHfaElementType.Context.Target.MaximumHfaElementCount;
                if (type.InstanceFieldSize.AsInt > maxSize)
                {
                    return(null);
                }

                return(currentHfaElementType);
            }
            else
            {
                Debug.Assert(
                    type.Context.Target.Architecture == TargetArchitecture.X86 ||
                    type.Context.Target.Architecture == TargetArchitecture.X64);

                return(null);
            }
        }
Ejemplo n.º 9
0
        public unsafe override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type)
        {
            // Use this constant to make the code below more laconic
            const ValueTypeShapeCharacteristics NotHA = ValueTypeShapeCharacteristics.None;

            Debug.Assert(type.IsValueType);

            TargetArchitecture targetArch = type.Context.Target.Architecture;

            if ((targetArch != TargetArchitecture.ARM) && (targetArch != TargetArchitecture.ARM64))
            {
                return(NotHA);
            }

            if (!type.IsValueType)
            {
                return(NotHA);
            }

            // There is no reason to compute the entire field layout for the HA type/flag if
            // the template type is not a universal generic type (information stored in rare flags on the EEType)
            TypeDesc templateType = type.ComputeTemplate(false);

            if (templateType != null && !templateType.IsCanonicalSubtype(CanonicalFormKind.Universal))
            {
                EEType *pEETemplate = templateType.GetRuntimeTypeHandle().ToEETypePtr();
                if (!pEETemplate->IsHFA)
                {
                    return(NotHA);
                }

                if (pEETemplate->RequiresAlign8)
                {
                    return(ValueTypeShapeCharacteristics.Float64Aggregate);
                }
                else
                {
                    return(ValueTypeShapeCharacteristics.Float32Aggregate);
                }
            }

            // Once this is done, the NativeLayoutFields on the type are initialized
            EnsureFieldLayoutLoadedForGenericType((DefType)type);
            Debug.Assert(type.NativeLayoutFields != null);

            // Empty types are not HA
            if (type.NativeLayoutFields.Length == 0)
            {
                return(NotHA);
            }

            // Find the common HA element type if any
            ValueTypeShapeCharacteristics haResultType = NotHA;

            for (int i = 0; i < type.NativeLayoutFields.Length; i++)
            {
                TypeDesc fieldType = type.NativeLayoutFields[i].FieldType;
                if (type.NativeLayoutFields[i].FieldStorage != NativeFormat.FieldStorage.Instance)
                {
                    continue;
                }

                // If a field isn't a DefType, then this type cannot be a HA type
                if (!(fieldType is DefType fieldDefType))
                {
                    return(NotHA);
                }

                // HA types cannot contain non-HA types
                ValueTypeShapeCharacteristics haFieldType = fieldDefType.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask;
                if (haFieldType == NotHA)
                {
                    return(NotHA);
                }

                if (haResultType == NotHA)
                {
                    haResultType = haFieldType;
                }
                else if (haResultType != haFieldType)
                {
                    return(NotHA); // If the field doesn't have the same HA type as the one we've looked at before, the type cannot be HA
                }
            }

            // If we didn't find any instance fields, then this can't be a HA type
            if (haResultType == NotHA)
            {
                return(NotHA);
            }

            int haElementSize = haResultType switch
            {
                ValueTypeShapeCharacteristics.Float32Aggregate => 4,
                ValueTypeShapeCharacteristics.Float64Aggregate => 8,
                ValueTypeShapeCharacteristics.Vector64Aggregate => 8,
                ValueTypeShapeCharacteristics.Vector128Aggregate => 16,
                _ => throw new ArgumentOutOfRangeException()
            };

            // Note that we check the total size, but do not perform any checks on number of fields:
            // - Type of fields can be HA valuetype itself
            // - Managed C++ HFA valuetypes have just one <alignment member> of type float to signal that
            //   the valuetype is HFA and explicitly specified size
            int maxSize = haElementSize * type.Context.Target.MaxHomogeneousAggregateElementCount;

            if (type.InstanceFieldSize.AsInt > maxSize)
            {
                return(NotHA);
            }

            return(haResultType);
        }
    }