/// <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(); } }
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); }
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++; }
private static LayoutInt CreateIndeterminateLayoutInt() { LayoutInt output = default(LayoutInt); output._value = -1; Debug.Assert(output.IsIndeterminate); return(output); }
public static LayoutInt Min(LayoutInt left, LayoutInt right) { if (left.IsIndeterminate || right.IsIndeterminate) { return(Indeterminate); } return(new LayoutInt(Math.Min(left._value, right._value))); }
private static LayoutInt ComputeBytesUsedInParentType(DefType type) { LayoutInt cumulativeInstanceFieldPos = LayoutInt.Zero; if (!type.IsValueType && type.HasBaseType) { cumulativeInstanceFieldPos = type.BaseType.InstanceByteCountUnaligned; } return(cumulativeInstanceFieldPos); }
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); }
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))); }
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); }
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); }
public FieldAndOffset(FieldDesc field, LayoutInt offset) { Field = field; Offset = offset; }
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); }
internal void InitializeOffset(LayoutInt offset) { Debug.Assert(_offset == FieldAndOffset.InvalidOffset || _offset == offset); _offset = offset; }
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); }