Exemplo n.º 1
0
        /// <summary>
        /// Given an alignment of the fields of a type, determine the alignment that is necessary for allocating the object on the GC heap
        /// </summary>
        /// <returns></returns>
        public LayoutInt GetObjectAlignment(LayoutInt fieldAlignment)
        {
            switch (Architecture)
            {
            case TargetArchitecture.ARM:
            case TargetArchitecture.Wasm32:
                // ARM & Wasm32 support two alignments for objects on the GC heap (4 byte and 8 byte)
                if (fieldAlignment.IsIndeterminate)
                {
                    return(LayoutInt.Indeterminate);
                }

                if (fieldAlignment.AsInt <= 4)
                {
                    return(new LayoutInt(4));
                }
                else
                {
                    return(new LayoutInt(8));
                }

            case TargetArchitecture.X64:
            case TargetArchitecture.ARM64:
                return(new LayoutInt(8));

            case TargetArchitecture.X86:
                return(new LayoutInt(4));

            default:
                throw new NotSupportedException();
            }
        }
Exemplo n.º 2
0
        public void ComputeInstanceLayout(InstanceLayoutKind layoutKind)
        {
            if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeFieldsLayout | FieldLayoutFlags.ComputedInstanceTypeLayout))
            {
                return;
            }

            var computedLayout = this.Context.GetLayoutAlgorithmForType(this).ComputeInstanceLayout(this, layoutKind);

            _instanceFieldSize          = computedLayout.FieldSize;
            _instanceFieldAlignment     = computedLayout.FieldAlignment;
            _instanceByteCountUnaligned = computedLayout.ByteCountUnaligned;
            _instanceByteAlignment      = computedLayout.ByteCountAlignment;

            if (computedLayout.Offsets != null)
            {
                foreach (var fieldAndOffset in computedLayout.Offsets)
                {
                    Debug.Assert(fieldAndOffset.Field.OwningType == this);
                    fieldAndOffset.Field.InitializeOffset(fieldAndOffset.Offset);
                }
                _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedInstanceTypeFieldsLayout);
            }

            _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedInstanceTypeLayout);
        }
Exemplo n.º 3
0
        public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defType, StaticLayoutKind layoutKind)
        {
            MetadataType type            = (MetadataType)defType;
            int          numStaticFields = 0;

            foreach (var field in type.GetFields())
            {
                if (!field.IsStatic || field.HasRva || field.IsLiteral)
                {
                    continue;
                }

                numStaticFields++;
            }

            ComputedStaticFieldLayout result;

            result.GcStatics          = new StaticsBlock();
            result.NonGcStatics       = new StaticsBlock();
            result.ThreadGcStatics    = new StaticsBlock();
            result.ThreadNonGcStatics = new StaticsBlock();

            if (numStaticFields == 0)
            {
                result.Offsets = Array.Empty <FieldAndOffset>();
                return(result);
            }

            result.Offsets = new FieldAndOffset[numStaticFields];

            PrepareRuntimeSpecificStaticFieldLayout(type.Context, ref result);

            int index = 0;

            foreach (var field in type.GetFields())
            {
                // Nonstatic fields, literal fields, and RVA mapped fields don't participate in layout
                if (!field.IsStatic || field.HasRva || field.IsLiteral)
                {
                    continue;
                }

                TypeDesc fieldType = field.FieldType;
                if (fieldType.IsByRef || (fieldType.IsValueType && ((DefType)fieldType).IsByRefLike))
                {
                    ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                }

                ref StaticsBlock block            = ref GetStaticsBlockForField(ref result, field);
                SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, type.Context.Target.DefaultPackingSize);

                block.Size            = LayoutInt.AlignUp(block.Size, sizeAndAlignment.Alignment);
                result.Offsets[index] = new FieldAndOffset(field, block.Size);
                block.Size            = block.Size + sizeAndAlignment.Size;

                block.LargestAlignment = LayoutInt.Max(block.LargestAlignment, sizeAndAlignment.Alignment);

                index++;
            }
Exemplo n.º 4
0
        private static LayoutInt CreateIndeterminateLayoutInt()
        {
            LayoutInt output = default(LayoutInt);

            output._value = -1;
            Debug.Assert(output.IsIndeterminate);
            return(output);
        }
Exemplo n.º 5
0
        public static LayoutInt Min(LayoutInt left, LayoutInt right)
        {
            if (left.IsIndeterminate || right.IsIndeterminate)
            {
                return(Indeterminate);
            }

            return(new LayoutInt(Math.Min(left._value, right._value)));
        }
Exemplo n.º 6
0
        private static LayoutInt ComputeBytesUsedInParentType(DefType type)
        {
            LayoutInt cumulativeInstanceFieldPos = LayoutInt.Zero;

            if (!type.IsValueType && type.HasBaseType)
            {
                cumulativeInstanceFieldPos = type.BaseType.InstanceByteCountUnaligned;
            }

            return(cumulativeInstanceFieldPos);
        }
Exemplo n.º 7
0
        private static ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType type, int numInstanceFields)
        {
            var offsets = new FieldAndOffset[numInstanceFields];

            // For types inheriting from another type, field offsets continue on from where they left off
            LayoutInt cumulativeInstanceFieldPos = ComputeBytesUsedInParentType(type);

            LayoutInt largestAlignmentRequirement = LayoutInt.One;
            int       fieldOrdinal = 0;
            int       packingSize  = ComputePackingSize(type);

            foreach (var field in type.GetFields())
            {
                if (field.IsStatic)
                {
                    continue;
                }

                var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, packingSize);

                largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement);

                cumulativeInstanceFieldPos = LayoutInt.AlignUp(cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment);
                offsets[fieldOrdinal]      = new FieldAndOffset(field, cumulativeInstanceFieldPos);
                cumulativeInstanceFieldPos = checked (cumulativeInstanceFieldPos + fieldSizeAndAlignment.Size);

                fieldOrdinal++;
            }

            if (type.IsValueType)
            {
                var layoutMetadata = type.GetClassLayout();
                cumulativeInstanceFieldPos = LayoutInt.Max(cumulativeInstanceFieldPos, new LayoutInt(layoutMetadata.Size));
            }

            SizeAndAlignment instanceByteSizeAndAlignment;
            var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, largestAlignmentRequirement, out instanceByteSizeAndAlignment);

            ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();

            computedLayout.FieldAlignment     = instanceSizeAndAlignment.Alignment;
            computedLayout.FieldSize          = instanceSizeAndAlignment.Size;
            computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size;
            computedLayout.ByteCountAlignment = instanceByteSizeAndAlignment.Alignment;
            computedLayout.Offsets            = offsets;

            return(computedLayout);
        }
Exemplo n.º 8
0
        public static LayoutInt AlignUp(LayoutInt value, LayoutInt alignment, TargetDetails target)
        {
            if (value.IsIndeterminate || alignment.IsIndeterminate)
            {
                // If value is already aligned to maximum possible alignment, then whatever
                // alignment is can't change value
                if (!value.IsIndeterminate)
                {
                    if (value.AsInt.AlignUp(target.MaximumAlignment) == value.AsInt)
                    {
                        return(value);
                    }
                }
                return(Indeterminate);
            }

            Debug.Assert(alignment._value <= target.MaximumAlignment);                               // Assert that the alignment handling for indeterminate types is safe
            Debug.Assert(alignment._value >= 1 || ((value._value == 0) && (alignment._value == 0))); // Alignment to less than one doesn't make sense, except for 0 to 0 alignment

            return(new LayoutInt(AlignmentHelper.AlignUp(value._value, alignment._value)));
        }
Exemplo n.º 9
0
        private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, out SizeAndAlignment byteCount)
        {
            SizeAndAlignment result;

            int targetPointerSize = type.Context.Target.PointerSize;

            // Pad the length of structs to be 1 if they are empty so we have no zero-length structures
            if (type.IsValueType && instanceSize == LayoutInt.Zero)
            {
                instanceSize = LayoutInt.One;
            }

            if (type.IsValueType)
            {
                instanceSize     = LayoutInt.AlignUp(instanceSize, alignment);
                result.Size      = instanceSize;
                result.Alignment = alignment;
            }
            else
            {
                result.Size      = new LayoutInt(targetPointerSize);
                result.Alignment = new LayoutInt(targetPointerSize);
                if (type.HasBaseType)
                {
                    alignment = LayoutInt.Max(alignment, type.BaseType.InstanceByteAlignment);
                }
            }

            // Determine the alignment needed by the type when allocated
            // This is target specific, and not just pointer sized due to
            // 8 byte alignment requirements on ARM for longs and doubles
            alignment = type.Context.Target.GetObjectAlignment(alignment);

            byteCount.Size      = instanceSize;
            byteCount.Alignment = alignment;

            return(result);
        }
Exemplo n.º 10
0
        private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, int packingSize)
        {
            SizeAndAlignment result;

            if (fieldType.IsDefType)
            {
                if (fieldType.IsValueType)
                {
                    DefType metadataType = (DefType)fieldType;
                    result.Size      = metadataType.InstanceFieldSize;
                    result.Alignment = metadataType.InstanceFieldAlignment;
                }
                else
                {
                    result.Size      = fieldType.Context.Target.LayoutPointerSize;
                    result.Alignment = fieldType.Context.Target.LayoutPointerSize;
                }
            }
            else if (fieldType.IsArray)
            {
                // This could use InstanceFieldSize/Alignment (and those results should match what's here)
                // but, its more efficient to just assume pointer size instead of fulling processing
                // the instance field layout of fieldType here.
                result.Size      = fieldType.Context.Target.LayoutPointerSize;
                result.Alignment = fieldType.Context.Target.LayoutPointerSize;
            }
            else
            {
                Debug.Assert(fieldType.IsPointer || fieldType.IsFunctionPointer);
                result.Size      = fieldType.Context.Target.LayoutPointerSize;
                result.Alignment = fieldType.Context.Target.LayoutPointerSize;
            }

            result.Alignment = LayoutInt.Min(result.Alignment, new LayoutInt(packingSize));

            return(result);
        }
Exemplo n.º 11
0
 public FieldAndOffset(FieldDesc field, LayoutInt offset)
 {
     Field  = field;
     Offset = offset;
 }
Exemplo n.º 12
0
        private static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType type, int numInstanceFields)
        {
            // Instance slice size is the total size of instance not including the base type.
            // It is calculated as the field whose offset and size add to the greatest value.
            LayoutInt cumulativeInstanceFieldPos =
                type.HasBaseType && !type.IsValueType ? type.BaseType.InstanceByteCount : LayoutInt.Zero;
            LayoutInt instanceSize = cumulativeInstanceFieldPos;

            var layoutMetadata = type.GetClassLayout();

            int       packingSize = ComputePackingSize(type);
            LayoutInt largestAlignmentRequired = LayoutInt.One;

            var offsets      = new FieldAndOffset[numInstanceFields];
            int fieldOrdinal = 0;

            foreach (var fieldAndOffset in layoutMetadata.Offsets)
            {
                var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldAndOffset.Field.FieldType, packingSize);

                largestAlignmentRequired = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequired);

                if (fieldAndOffset.Offset == FieldAndOffset.InvalidOffset)
                {
                    throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
                }

                LayoutInt computedOffset = fieldAndOffset.Offset + cumulativeInstanceFieldPos;

                if (fieldAndOffset.Field.FieldType.IsGCPointer && !computedOffset.IsIndeterminate)
                {
                    int offsetModulo = computedOffset.AsInt % type.Context.Target.PointerSize;
                    if (offsetModulo != 0)
                    {
                        // GC pointers MUST be aligned.
                        throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadExplicitLayout, type, fieldAndOffset.Offset.ToStringInvariant());
                    }
                }

                offsets[fieldOrdinal] = new FieldAndOffset(fieldAndOffset.Field, computedOffset);

                LayoutInt fieldExtent = computedOffset + fieldSizeAndAlignment.Size;
                instanceSize = LayoutInt.Max(fieldExtent, instanceSize);

                fieldOrdinal++;
            }

            if (type.IsValueType)
            {
                instanceSize = LayoutInt.Max(new LayoutInt(layoutMetadata.Size), instanceSize);
            }

            SizeAndAlignment instanceByteSizeAndAlignment;
            var instanceSizeAndAlignment = ComputeInstanceSize(type, instanceSize, largestAlignmentRequired, out instanceByteSizeAndAlignment);

            ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();

            computedLayout.FieldAlignment     = instanceSizeAndAlignment.Alignment;
            computedLayout.FieldSize          = instanceSizeAndAlignment.Size;
            computedLayout.ByteCountUnaligned = instanceByteSizeAndAlignment.Size;
            computedLayout.ByteCountAlignment = instanceByteSizeAndAlignment.Alignment;
            computedLayout.Offsets            = offsets;

            return(computedLayout);
        }
Exemplo n.º 13
0
 internal void InitializeOffset(LayoutInt offset)
 {
     Debug.Assert(_offset == FieldAndOffset.InvalidOffset || _offset == offset);
     _offset = offset;
 }
Exemplo n.º 14
0
        public unsafe override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defType, StaticLayoutKind layoutKind)
        {
            MetadataType type            = (MetadataType)defType;
            int          numStaticFields = 0;

            foreach (var field in type.GetFields())
            {
                if (!field.IsStatic || field.HasRva || field.IsLiteral)
                {
                    continue;
                }

                numStaticFields++;
            }

            ComputedStaticFieldLayout result;

            result.GcStatics     = new StaticsBlock();
            result.NonGcStatics  = new StaticsBlock();
            result.ThreadStatics = new StaticsBlock();

            if (numStaticFields == 0)
            {
                result.Offsets = Array.Empty <FieldAndOffset>();
                return(result);
            }

            result.Offsets = new FieldAndOffset[numStaticFields];

            PrepareRuntimeSpecificStaticFieldLayout(type.Context, ref result);

            int index = 0;

            foreach (var field in type.GetFields())
            {
                // Nonstatic fields, literal fields, and RVA mapped fields don't participate in layout
                if (!field.IsStatic || field.HasRva || field.IsLiteral)
                {
                    continue;
                }

                StaticsBlock *block =
                    field.IsThreadStatic ? &result.ThreadStatics :
                    field.HasGCStaticBase ? &result.GcStatics :
                    &result.NonGcStatics;

                SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, type.Context.Target.DefaultPackingSize);

                block->Size           = LayoutInt.AlignUp(block->Size, sizeAndAlignment.Alignment);
                result.Offsets[index] = new FieldAndOffset(field, block->Size);
                block->Size           = block->Size + sizeAndAlignment.Size;

                block->LargestAlignment = LayoutInt.Max(block->LargestAlignment, sizeAndAlignment.Alignment);

                index++;
            }

            FinalizeRuntimeSpecificStaticFieldLayout(type.Context, ref result);

            return(result);
        }