Skip to content

Commit 509d6c3

Browse files
jkoritzinskyjkotas
andauthored
Change all "unmanaged" (no GC fields) sequential types to have sequential layout. (#61759)
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
1 parent fbabdb6 commit 509d6c3

File tree

20 files changed

+288
-319
lines changed

20 files changed

+288
-319
lines changed

src/coreclr/debug/ee/debugger.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4360,7 +4360,7 @@ SIZE_T GetSetFrameHelper::GetValueClassSize(MetaSig* pSig)
43604360
// - but we don't care if it's shared (since it will be the same size either way)
43614361
_ASSERTE(!vcType.IsNull() && vcType.IsValueType());
43624362

4363-
return (vcType.GetMethodTable()->GetAlignedNumInstanceFieldBytes());
4363+
return (vcType.GetMethodTable()->GetNumInstanceFieldBytes());
43644364
}
43654365

43664366
//

src/coreclr/inc/readytorun.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@
1515
#define READYTORUN_SIGNATURE 0x00525452 // 'RTR'
1616

1717
// Keep these in sync with src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs
18-
#define READYTORUN_MAJOR_VERSION 0x0005
19-
#define READYTORUN_MINOR_VERSION 0x0004
18+
#define READYTORUN_MAJOR_VERSION 0x0006
19+
#define READYTORUN_MINOR_VERSION 0x0000
2020

21-
#define MINIMUM_READYTORUN_MAJOR_VERSION 0x003
21+
#define MINIMUM_READYTORUN_MAJOR_VERSION 0x006
2222

2323
// R2R Version 2.1 adds the InliningInfo section
2424
// R2R Version 2.2 adds the ProfileDataInfo section
2525
// R2R Version 3.0 changes calling conventions to correctly handle explicit structures to spec.
2626
// R2R 3.0 is not backward compatible with 2.x.
27+
// R2R Version 6.0 changes managed layout for sequential types with any unmanaged non-blittable fields.
28+
// R2R 6.0 is not backward compatible with 5.x or earlier.
2729

2830
struct READYTORUN_CORE_HEADER
2931
{

src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ internal struct ReadyToRunHeaderConstants
1414
{
1515
public const uint Signature = 0x00525452; // 'RTR'
1616

17-
public const ushort CurrentMajorVersion = 5;
18-
public const ushort CurrentMinorVersion = 4;
17+
public const ushort CurrentMajorVersion = 6;
18+
public const ushort CurrentMinorVersion = 0;
1919
}
2020

2121
#pragma warning disable 0169

src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs

Lines changed: 26 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
103103
type.Context.Target.GetWellKnownTypeSize(type),
104104
type.Context.Target.GetWellKnownTypeAlignment(type),
105105
0,
106-
alignUpInstanceByteSize: true,
107106
out instanceByteSizeAndAlignment
108107
);
109108

@@ -291,8 +290,6 @@ protected virtual void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContex
291290
{
292291
}
293292

294-
protected virtual bool AlignUpInstanceByteSizeForExplicitFieldLayoutCompatQuirk(TypeDesc type) => true;
295-
296293
protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType type, int numInstanceFields)
297294
{
298295
// Instance slice size is the total size of instance not including the base type.
@@ -312,7 +309,7 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty
312309
foreach (var fieldAndOffset in layoutMetadata.Offsets)
313310
{
314311
TypeDesc fieldType = fieldAndOffset.Field.FieldType;
315-
var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable);
312+
var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType.UnderlyingType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable);
316313
if (!fieldLayoutAbiStable)
317314
layoutAbiStable = false;
318315

@@ -355,7 +352,6 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty
355352
instanceSize,
356353
largestAlignmentRequired,
357354
layoutMetadata.Size,
358-
alignUpInstanceByteSize: AlignUpInstanceByteSizeForExplicitFieldLayoutCompatQuirk(type),
359355
out instanceByteSizeAndAlignment);
360356

361357
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
@@ -398,7 +394,7 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType
398394
if (field.IsStatic)
399395
continue;
400396

401-
var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable);
397+
var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType.UnderlyingType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable);
402398
if (!fieldLayoutAbiStable)
403399
layoutAbiStable = false;
404400

@@ -417,7 +413,6 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType
417413
cumulativeInstanceFieldPos + offsetBias,
418414
largestAlignmentRequirement,
419415
layoutMetadata.Size,
420-
alignUpInstanceByteSize: true,
421416
out instanceByteSizeAndAlignment);
422417

423418
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
@@ -442,8 +437,8 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
442437
bool hasLayout = type.HasLayout();
443438
var layoutMetadata = type.GetClassLayout();
444439

445-
int packingSize = ComputePackingSize(type, layoutMetadata);
446-
packingSize = Math.Min(context.Target.MaximumAutoLayoutPackingSize, packingSize);
440+
// Auto-layout in CoreCLR does not respect packing size.
441+
int packingSize = type.Context.Target.MaximumAlignment;
447442

448443
var offsets = new FieldAndOffset[numInstanceFields];
449444
int fieldOrdinal = 0;
@@ -543,7 +538,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
543538
LayoutInt offsetBias = LayoutInt.Zero;
544539
if (!type.IsValueType && cumulativeInstanceFieldPos != LayoutInt.Zero && type.Context.Target.Architecture == TargetArchitecture.X86)
545540
{
546-
offsetBias = new LayoutInt(type.Context.Target.PointerSize);
541+
offsetBias = type.Context.Target.LayoutPointerSize;
547542
cumulativeInstanceFieldPos -= offsetBias;
548543
}
549544

@@ -650,29 +645,14 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
650645
// Place value class fields last
651646
for (int i = 0; i < instanceValueClassFieldsArr.Length; i++)
652647
{
653-
// If the field has an indeterminate alignment, align the cumulative field offset to the indeterminate value
654-
// Otherwise, align the cumulative field offset to the PointerSize
655-
// This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments
648+
// Align the cumulative field offset to the indeterminate value
656649
var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(instanceValueClassFieldsArr[i].FieldType, hasLayout, packingSize, out bool fieldLayoutAbiStable);
657650
if (!fieldLayoutAbiStable)
658651
layoutAbiStable = false;
659652

660-
if (fieldSizeAndAlignment.Alignment.IsIndeterminate)
661-
{
662-
cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, context.Target);
663-
}
664-
else
665-
{
666-
LayoutInt AlignmentRequired = LayoutInt.Max(fieldSizeAndAlignment.Alignment, context.Target.LayoutPointerSize);
667-
cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, AlignmentRequired, context.Target);
668-
}
653+
cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, context.Target);
669654
offsets[fieldOrdinal] = new FieldAndOffset(instanceValueClassFieldsArr[i], cumulativeInstanceFieldPos + offsetBias);
670-
671-
// If the field has an indeterminate size, align the cumulative field offset to the indeterminate value
672-
// Otherwise, align the cumulative field offset to the aligned-instance field size
673-
// This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments
674-
LayoutInt alignedInstanceFieldBytes = fieldSizeAndAlignment.Size.IsIndeterminate ? fieldSizeAndAlignment.Size : GetAlignedNumInstanceFieldBytes(fieldSizeAndAlignment.Size);
675-
cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + alignedInstanceFieldBytes);
655+
cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + fieldSizeAndAlignment.Size);
676656

677657
fieldOrdinal++;
678658
}
@@ -687,11 +667,18 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
687667
}
688668
else if (cumulativeInstanceFieldPos.AsInt > context.Target.PointerSize)
689669
{
690-
minAlign = context.Target.LayoutPointerSize;
691-
if (requiresAlign8 && minAlign.AsInt == 4)
670+
if (requiresAlign8)
692671
{
693672
minAlign = new LayoutInt(8);
694673
}
674+
else if (type.ContainsGCPointers)
675+
{
676+
minAlign = context.Target.LayoutPointerSize;
677+
}
678+
else
679+
{
680+
minAlign = largestAlignmentRequired;
681+
}
695682
}
696683
else
697684
{
@@ -705,8 +692,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
705692
cumulativeInstanceFieldPos + offsetBias,
706693
minAlign,
707694
classLayoutSize: 0,
708-
alignUpInstanceByteSize: true,
709-
out instanceByteSizeAndAlignment);
695+
byteCount: out instanceByteSizeAndAlignment);
710696

711697
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
712698
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
@@ -790,10 +776,10 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType,
790776
{
791777
if (fieldType.IsValueType)
792778
{
793-
DefType metadataType = (DefType)fieldType;
794-
result.Size = metadataType.InstanceFieldSize;
795-
result.Alignment = metadataType.InstanceFieldAlignment;
796-
layoutAbiStable = metadataType.LayoutAbiStable;
779+
DefType defType = (DefType)fieldType;
780+
result.Size = defType.InstanceFieldSize;
781+
result.Alignment = defType.InstanceFieldAlignment;
782+
layoutAbiStable = defType.LayoutAbiStable;
797783
}
798784
else
799785
{
@@ -816,27 +802,24 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType,
816802
result.Alignment = fieldType.Context.Target.LayoutPointerSize;
817803
}
818804

805+
// For non-auto layouts, we need to respect tighter packing requests for alignment.
819806
if (hasLayout)
820807
{
821808
result.Alignment = LayoutInt.Min(result.Alignment, new LayoutInt(packingSize));
822809
}
823-
else
824-
{
825-
result.Alignment = LayoutInt.Min(result.Alignment, fieldType.Context.Target.GetObjectAlignment(result.Alignment));
826-
}
827810

828811
return result;
829812
}
830813

831814
private static int ComputePackingSize(MetadataType type, ClassLayoutMetadata layoutMetadata)
832815
{
833816
if (layoutMetadata.PackingSize == 0)
834-
return type.Context.Target.DefaultPackingSize;
817+
return type.Context.Target.MaximumAlignment;
835818
else
836819
return layoutMetadata.PackingSize;
837820
}
838821

839-
private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, int classLayoutSize, bool alignUpInstanceByteSize, out SizeAndAlignment byteCount)
822+
private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, int classLayoutSize, out SizeAndAlignment byteCount)
840823
{
841824
SizeAndAlignment result;
842825

@@ -864,9 +847,7 @@ private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt
864847
{
865848
if (type.IsValueType)
866849
{
867-
instanceSize = LayoutInt.AlignUp(instanceSize,
868-
alignUpInstanceByteSize ? alignment : LayoutInt.Min(alignment, target.LayoutPointerSize),
869-
target);
850+
instanceSize = LayoutInt.AlignUp(instanceSize, alignment, target);
870851
}
871852
}
872853

src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -324,20 +324,5 @@ public int MaxHomogeneousAggregateElementCount
324324
return 4;
325325
}
326326
}
327-
328-
public int MaximumAutoLayoutPackingSize
329-
{
330-
get
331-
{
332-
if (Abi == TargetAbi.CoreRT)
333-
{
334-
if (Architecture == TargetArchitecture.X86)
335-
{
336-
return PointerSize;
337-
}
338-
}
339-
return MaximumAlignment;
340-
}
341-
}
342327
}
343328
}

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs

Lines changed: 14 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,9 @@ protected override ModuleFieldLayout CreateValueFromKey(EcmaModule module)
196196
}
197197
}
198198

199-
if (nonGcBytes[StaticIndex.Regular] != 0 ||
199+
if (nonGcBytes[StaticIndex.Regular] != 0 ||
200200
nonGcBytes[StaticIndex.ThreadLocal] != 0 ||
201-
gcBytes[StaticIndex.Regular] != 0 ||
201+
gcBytes[StaticIndex.Regular] != 0 ||
202202
gcBytes[StaticIndex.ThreadLocal] != 0)
203203
{
204204
OffsetsForType offsetsForType = new OffsetsForType(LayoutInt.Indeterminate, LayoutInt.Indeterminate, LayoutInt.Indeterminate, LayoutInt.Indeterminate);
@@ -290,14 +290,14 @@ private void GetElementTypeInfoGeneric(
290290
}
291291

292292
private void GetElementTypeInfo(
293-
EcmaModule module,
293+
EcmaModule module,
294294
FieldDesc fieldDesc,
295-
EntityHandle valueTypeHandle,
295+
EntityHandle valueTypeHandle,
296296
CorElementType elementType,
297297
int pointerSize,
298298
bool moduleLayout,
299-
out int alignment,
300-
out int size,
299+
out int alignment,
300+
out int size,
301301
out bool isGcPointerField,
302302
out bool isGcBoxedField)
303303
{
@@ -357,7 +357,7 @@ private void GetElementTypeInfo(
357357
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, fieldDesc.OwningType);
358358
break;
359359

360-
// Statics for valuetypes where the valuetype is defined in this module are handled here.
360+
// Statics for valuetypes where the valuetype is defined in this module are handled here.
361361
// Other valuetype statics utilize the pessimistic model below.
362362
case CorElementType.ELEMENT_TYPE_VALUETYPE:
363363
if (IsTypeByRefLike(valueTypeHandle, module.MetadataReader))
@@ -522,7 +522,7 @@ public FieldAndOffset[] CalculateTypeLayout(DefType defType, EcmaModule module,
522522
offsetsForType.GcOffsets[StaticIndex.ThreadLocal],
523523
};
524524

525-
LayoutInt[] gcPointerFieldOffsets = new LayoutInt[StaticIndex.Count]
525+
LayoutInt[] gcPointerFieldOffsets = new LayoutInt[StaticIndex.Count]
526526
{
527527
offsetsForType.GcOffsets[StaticIndex.Regular] + new LayoutInt(gcBoxedCount[StaticIndex.Regular] * pointerSize),
528528
offsetsForType.GcOffsets[StaticIndex.ThreadLocal] + new LayoutInt(gcBoxedCount[StaticIndex.ThreadLocal] * pointerSize)
@@ -768,10 +768,10 @@ private class ModuleFieldLayout
768768
private ConcurrentDictionary<DefType, FieldAndOffset[]> _genericTypeToFieldMap;
769769

770770
public ModuleFieldLayout(
771-
EcmaModule module,
772-
StaticsBlock gcStatics,
773-
StaticsBlock nonGcStatics,
774-
StaticsBlock threadGcStatics,
771+
EcmaModule module,
772+
StaticsBlock gcStatics,
773+
StaticsBlock nonGcStatics,
774+
StaticsBlock threadGcStatics,
775775
StaticsBlock threadNonGcStatics,
776776
IReadOnlyDictionary<TypeDefinitionHandle, OffsetsForType> typeOffsets)
777777
{
@@ -802,8 +802,7 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada
802802
{
803803
return ComputeExplicitFieldLayout(type, numInstanceFields);
804804
}
805-
else
806-
if (type.IsEnum || MarshalUtils.IsBlittableType(type) || IsManagedSequentialType(type))
805+
else if (type.IsSequentialLayout && !type.ContainsGCPointers)
807806
{
808807
return ComputeSequentialFieldLayout(type, numInstanceFields);
809808
}
@@ -814,7 +813,7 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada
814813
}
815814

816815
/// <summary>
817-
/// This method decides whether the type needs aligned base offset in order to have layout resilient to
816+
/// This method decides whether the type needs aligned base offset in order to have layout resilient to
818817
/// base class layout changes.
819818
/// </summary>
820819
protected override void AlignBaseOffsetIfNecessary(MetadataType type, ref LayoutInt baseOffset, bool requiresAlign8, bool requiresAlignedBase)
@@ -826,44 +825,5 @@ protected override void AlignBaseOffsetIfNecessary(MetadataType type, ref Layout
826825
baseOffset = LayoutInt.AlignUp(baseOffset, alignment, type.Context.Target);
827826
}
828827
}
829-
830-
protected override bool AlignUpInstanceByteSizeForExplicitFieldLayoutCompatQuirk(TypeDesc type)
831-
{
832-
return MarshalUtils.IsBlittableType(type) || IsManagedSequentialType(type);
833-
}
834-
835-
public static bool IsManagedSequentialType(TypeDesc type)
836-
{
837-
if (type.IsPointer)
838-
{
839-
return true;
840-
}
841-
842-
if (!type.IsValueType)
843-
{
844-
return false;
845-
}
846-
847-
MetadataType metadataType = (MetadataType)type;
848-
if (metadataType.IsExplicitLayout || !metadataType.IsSequentialLayout)
849-
{
850-
return false;
851-
}
852-
853-
if (type.IsPrimitive)
854-
{
855-
return true;
856-
}
857-
858-
foreach (FieldDesc field in type.GetFields())
859-
{
860-
if (!field.IsStatic && !IsManagedSequentialType(field.FieldType.UnderlyingType))
861-
{
862-
return false;
863-
}
864-
}
865-
866-
return true;
867-
}
868828
}
869829
}

0 commit comments

Comments
 (0)