Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,16 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
// between base type and the current type.
LayoutInt cumulativeInstanceFieldPos = CalculateFieldBaseOffset(type, requiresAlign8, requiresAlignedBase: false);
LayoutInt offsetBias = LayoutInt.Zero;
if (!type.IsValueType && cumulativeInstanceFieldPos != LayoutInt.Zero && type.Context.Target.Architecture == TargetArchitecture.X86)

// The following conditional statement mimics the behavior of MethodTableBuilder::PlaceInstanceFields;
// the fundamental difference between CoreCLR native runtime and Crossgen2 regarding field placement is
// that the native runtime doesn't count the method table pointer at the beginning of reference types as a 'field'
// so that the first field in a class has offset 0 while its 'real' offset from the 'this' pointer is LayoutPointerSize.
// On ARM32, native runtime employs a special logic internally calculating the field offsets relative to the 'this'
// pointer (the Crossgen2 way) to ensure 8-alignment for longs and doubles as required by the ARM32 ISA. Please note
// that for 16-alignment used by Vector128 this logic actually ensures that the fields are 16-misaligned
// (they are 16-aligned after the 4-byte or 8-byte method table pointer).
if (!type.IsValueType && cumulativeInstanceFieldPos != LayoutInt.Zero && type.Context.Target.Architecture != TargetArchitecture.ARM)
{
offsetBias = type.Context.Target.LayoutPointerSize;
cumulativeInstanceFieldPos -= offsetBias;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ public struct StructStructByte_UInt128StructAuto
public StructByte fld1;
public Auto.UInt128Struct fld2;
}

[StructLayout(LayoutKind.Sequential)]
public class Class16Align
{
Vector128<byte> vector16Align;
}
}

namespace Auto
Expand Down Expand Up @@ -441,6 +447,12 @@ public struct Int128Struct
{
Int128 fld1;
}

[StructLayout(LayoutKind.Sequential)]
public class Class16Align
{
Vector128<byte> vector16Align;
}
}

namespace IsByRefLike
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,28 @@ public void TestSequentialTypeLayoutStructEmbedded()
}
}

[Fact]
public void TestSequentialTypeLayoutClass16Align()
{
MetadataType classType = _testModule.GetType("Sequential", "Class16Align");
Assert.Equal(0x18, classType.InstanceByteCount.AsInt);
foreach (var f in classType.GetFields())
{
if (f.IsStatic)
continue;

switch (f.Name)
{
case "vector16Align":
Assert.Equal(0x8, f.Offset.AsInt);
break;
default:
Assert.True(false);
break;
}
}
}

[Fact]
public void TestAutoLayoutStruct()
{
Expand Down Expand Up @@ -782,6 +804,28 @@ public void TestAutoTypeLayoutMinPacking(WellKnownType type, int expectedSize)
Assert.Equal(expectedSize, inst.InstanceFieldSize.AsInt);
}

[Fact]
public void TestAutoTypeLayoutClass16Align()
{
MetadataType classType = _testModule.GetType("Auto", "Class16Align");
Assert.Equal(0x18, classType.InstanceByteCount.AsInt);
foreach (var f in classType.GetFields())
{
if (f.IsStatic)
continue;

switch (f.Name)
{
case "vector16Align":
Assert.Equal(0x8, f.Offset.AsInt);
break;
default:
Assert.True(false);
break;
}
}
}

[Fact]
public void TestTypeContainsGCPointers()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ private void CommonClassLayoutTestBits(ModuleDesc testModule,
AssertClassIndeterminateSize(context, genOfUL, expectedIndeterminateByteAlignment);
}

/* This test exercises universal shared generic layout that is currently unsupported and known to be buggy.
[Fact]
public void TestClassLayout()
{
Expand Down Expand Up @@ -511,5 +512,6 @@ public void TestClassLayout()
Assert.Equal(LayoutInt.Indeterminate, genOfUI.GetFields().First().Offset);
Assert.Equal(LayoutInt.Indeterminate, genOfUL.GetFields().First().Offset);
}
*/
}
}