Skip to content

Commit f7c4c8c

Browse files
Implement support for ExtendedLayoutKind.CUnion (#123052)
Co-authored-by: Copilot <[email protected]>
1 parent 0f28558 commit f7c4c8c

File tree

21 files changed

+622
-6
lines changed

21 files changed

+622
-6
lines changed

src/coreclr/inc/corhdr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ typedef enum CorTypeAttr
329329
enum class CorExtendedLayoutKind
330330
{
331331
CStruct = 0, // C-style struct
332+
CUnion = 1, // C-style union
332333
};
333334

334335
// Macros for accessing the members of the CorTypeAttr.

src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2123,6 +2123,14 @@ private uint getClassAttribsInternal(TypeDesc type)
21232123

21242124
if (metadataType.IsInlineArray)
21252125
result |= CorInfoFlag.CORINFO_FLG_INDEXABLE_FIELDS;
2126+
2127+
if (metadataType.IsExtendedLayout)
2128+
{
2129+
if (metadataType.GetClassLayout().Kind == MetadataLayoutKind.CUnion)
2130+
{
2131+
result |= CorInfoFlag.CORINFO_FLG_OVERLAPPING_FIELDS;
2132+
}
2133+
}
21262134
}
21272135

21282136
if (type.IsCanonicalSubtype(CanonicalFormKind.Any))

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

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType
498498

499499
protected ComputedInstanceFieldLayout ComputeCStructFieldLayout(MetadataType type, int numInstanceFields)
500500
{
501-
if (type.ContainsGCPointers || !type.IsValueType)
501+
if (type.ContainsGCPointers || type.IsByRefLike || !type.IsValueType)
502502
{
503503
// CStruct layout algorithm does not support GC pointers.
504504
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
@@ -581,6 +581,91 @@ protected ComputedInstanceFieldLayout ComputeCStructFieldLayout(MetadataType typ
581581
return computedLayout;
582582
}
583583

584+
protected ComputedInstanceFieldLayout ComputeCUnionFieldLayout(MetadataType type, int numInstanceFields)
585+
{
586+
if (type.ContainsGCPointers || type.IsByRefLike || !type.IsValueType)
587+
{
588+
// CUnion layout algorithm does not support GC pointers.
589+
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
590+
}
591+
592+
var offsets = new FieldAndOffset[numInstanceFields];
593+
594+
LayoutInt largestFieldSize = LayoutInt.Zero;
595+
LayoutInt largestAlignmentRequirement = LayoutInt.One;
596+
int fieldOrdinal = 0;
597+
int packingSize = type.Context.Target.MaximumAlignment;
598+
bool layoutAbiStable = true;
599+
bool hasAutoLayoutField = false;
600+
bool hasInt128Field = false;
601+
bool hasVectorTField = false;
602+
603+
foreach (var field in type.GetFields())
604+
{
605+
if (field.IsStatic)
606+
continue;
607+
608+
var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType.UnderlyingType, hasLayout: true, packingSize, out ComputedFieldData fieldData);
609+
if (!fieldData.LayoutAbiStable)
610+
layoutAbiStable = false;
611+
if (fieldData.HasAutoLayout)
612+
hasAutoLayoutField = true;
613+
if (fieldData.HasInt128Field)
614+
hasInt128Field = true;
615+
if (fieldData.HasVectorTField)
616+
hasVectorTField = true;
617+
618+
largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement);
619+
largestFieldSize = LayoutInt.Max(fieldSizeAndAlignment.Size, largestFieldSize);
620+
621+
// All fields are placed at offset 0 in a union
622+
offsets[fieldOrdinal] = new FieldAndOffset(field, LayoutInt.Zero);
623+
624+
fieldOrdinal++;
625+
}
626+
627+
if (hasAutoLayoutField)
628+
{
629+
// CUnion does not support auto layout fields
630+
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
631+
}
632+
633+
if (largestFieldSize == LayoutInt.Zero)
634+
{
635+
// CUnion cannot have zero size.
636+
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
637+
}
638+
639+
if (type.IsInlineArray)
640+
{
641+
// CUnion types cannot be inline arrays
642+
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
643+
}
644+
645+
SizeAndAlignment instanceByteSizeAndAlignment;
646+
var instanceSizeAndAlignment = ComputeInstanceSize(
647+
type,
648+
largestFieldSize,
649+
largestAlignmentRequirement,
650+
classLayoutSize: 0, // CUnion does not use the size from metadata.
651+
out instanceByteSizeAndAlignment);
652+
653+
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout
654+
{
655+
IsAutoLayoutOrHasAutoLayoutFields = false,
656+
IsInt128OrHasInt128Fields = hasInt128Field,
657+
IsVectorTOrHasVectorTFields = hasVectorTField,
658+
FieldAlignment = instanceSizeAndAlignment.Alignment,
659+
FieldSize = instanceSizeAndAlignment.Size,
660+
ByteCountUnaligned = instanceByteSizeAndAlignment.Size,
661+
ByteCountAlignment = instanceByteSizeAndAlignment.Alignment,
662+
Offsets = offsets,
663+
LayoutAbiStable = layoutAbiStable
664+
};
665+
666+
return computedLayout;
667+
}
668+
584669
private static void AdjustForInlineArray(
585670
MetadataType type,
586671
int instanceFieldCount,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ public enum MetadataLayoutKind
125125
Auto,
126126
Sequential,
127127
Explicit,
128-
CStruct
128+
CStruct,
129+
CUnion
129130
}
130131
}

src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,9 @@ public override ClassLayoutMetadata GetClassLayout()
586586
case 0:
587587
layoutKind = MetadataLayoutKind.CStruct;
588588
break;
589+
case 1:
590+
layoutKind = MetadataLayoutKind.CUnion;
591+
break;
589592
default:
590593
ThrowHelper.ThrowTypeLoadException(this);
591594
return default; // Invalid kind value

src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalUtils.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static bool IsBlittableType(TypeDesc type)
3131

3232
if (mdType.IsExtendedLayout)
3333
{
34-
return mdType.GetClassLayout().Kind is MetadataLayoutKind.CStruct;
34+
return mdType.GetClassLayout().Kind is MetadataLayoutKind.CStruct or MetadataLayoutKind.CUnion;
3535
}
3636

3737
if (mdType.IsAutoLayout)

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerMetadataFieldLayoutAlgorithm.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada
4949
// all types without GC references (ie C# unmanaged types).
5050
MetadataLayoutKind.Sequential when !type.ContainsGCPointers => ComputeSequentialFieldLayout(type, numInstanceFields, layoutMetadata),
5151
MetadataLayoutKind.CStruct => ComputeCStructFieldLayout(type, numInstanceFields),
52+
MetadataLayoutKind.CUnion => ComputeCUnionFieldLayout(type, numInstanceFields),
5253
_ => ComputeAutoFieldLayout(type, numInstanceFields, layoutMetadata),
5354
};
5455
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,8 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada
612612
{
613613
case MetadataLayoutKind.CStruct:
614614
return ComputeCStructFieldLayout(type, numInstanceFields);
615+
case MetadataLayoutKind.CUnion:
616+
return ComputeCUnionFieldLayout(type, numInstanceFields);
615617
case MetadataLayoutKind.Explicit:
616618
// Works around https://github.com/dotnet/runtime/issues/102868
617619
if (type is { IsValueType: false, BaseType.IsSequentialLayout: true })

src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TestMetadataFieldLayoutAlgorithm.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada
4343
{
4444
return ComputeCStructFieldLayout(type, numInstanceFields);
4545
}
46+
else if (layoutMetadata.Kind == MetadataLayoutKind.CUnion)
47+
{
48+
return ComputeCUnionFieldLayout(type, numInstanceFields);
49+
}
4650
else
4751
{
4852
return ComputeAutoFieldLayout(type, numInstanceFields, layoutMetadata);

src/coreclr/vm/class.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,8 @@ class EEClassLayoutInfo
342342
Auto = 0, // Make sure Auto is the default value as the default-constructed value represents the "auto layout" case
343343
Sequential,
344344
Explicit,
345-
CStruct
345+
CStruct,
346+
CUnion
346347
};
347348
private:
348349
enum {
@@ -496,6 +497,12 @@ class EEClassLayoutInfo
496497
ULONG cFields
497498
);
498499

500+
ULONG InitializeCUnionFieldLayout(
501+
FieldDesc* pFields,
502+
MethodTable** pByValueClassCache,
503+
ULONG cFields
504+
);
505+
499506
private:
500507
void SetIsZeroSized(BOOL isZeroSized)
501508
{

0 commit comments

Comments
 (0)