From 9663d5c5ae5126abc24f264b829e93c266df4afe Mon Sep 17 00:00:00 2001 From: Tomas Date: Fri, 16 Apr 2021 23:58:05 +0200 Subject: [PATCH 01/16] Fix regression test 46239 and improve runtime logging The regression test src\tests\JIT\Regressions\JitBlue\Runtime_46239 exercises various interesting corner cases of type layout that weren't handled properly in Crossgen2 on x86 and ARM[32]. This change fixes the remaining deficiencies and it also adds provisions for better runtime logging upon type layout mismatches. Thanks Tomas --- .../Common/MetadataFieldLayoutAlgorithm.cs | 37 +++++-- .../ReadyToRunMetadataFieldLayoutAlgorithm.cs | 2 + src/coreclr/vm/jitinterface.cpp | 100 ++++++++++++++++-- 3 files changed, 121 insertions(+), 18 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index f7372ba0d6edd..c654283c16ab1 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -103,6 +103,7 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp type.Context.Target.GetWellKnownTypeSize(type), type.Context.Target.GetWellKnownTypeAlignment(type), 0, + alignUpInstanceByteSize: true, out instanceByteSizeAndAlignment ); @@ -304,17 +305,19 @@ protected virtual void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContex { } - protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType type, int numInstanceFields) + protected virtual bool IsBlittableOrManagedSequential(TypeDesc type) => false; + + protected 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 offsetBias = !type.IsValueType ? new LayoutInt(type.Context.Target.PointerSize) : LayoutInt.Zero; LayoutInt cumulativeInstanceFieldPos = type.HasBaseType && !type.IsValueType ? type.BaseType.InstanceByteCount : LayoutInt.Zero; - LayoutInt instanceSize = cumulativeInstanceFieldPos; cumulativeInstanceFieldPos -= offsetBias; var layoutMetadata = type.GetClassLayout(); + LayoutInt instanceSize = cumulativeInstanceFieldPos + new LayoutInt(layoutMetadata.Size); int packingSize = ComputePackingSize(type, layoutMetadata); LayoutInt largestAlignmentRequired = LayoutInt.One; @@ -349,6 +352,7 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata ); if (needsToBeAligned) { + largestAlignmentRequired = LayoutInt.Max(largestAlignmentRequired, type.Context.Target.LayoutPointerSize); int offsetModulo = computedOffset.AsInt % type.Context.Target.PointerSize; if (offsetModulo != 0) { @@ -365,7 +369,12 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata } SizeAndAlignment instanceByteSizeAndAlignment; - var instanceSizeAndAlignment = ComputeInstanceSize(type, instanceSize, largestAlignmentRequired, layoutMetadata.Size, out instanceByteSizeAndAlignment); + var instanceSizeAndAlignment = ComputeInstanceSize(type, + instanceSize, + largestAlignmentRequired, + layoutMetadata.Size, + alignUpInstanceByteSize: IsBlittableOrManagedSequential(type), + out instanceByteSizeAndAlignment); ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; @@ -375,7 +384,6 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata computedLayout.Offsets = offsets; computedLayout.LayoutAbiStable = layoutAbiStable; - ExplicitLayoutValidator.Validate(type, computedLayout); return computedLayout; @@ -422,7 +430,13 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType } SizeAndAlignment instanceByteSizeAndAlignment; - var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos + offsetBias, largestAlignmentRequirement, layoutMetadata.Size, out instanceByteSizeAndAlignment); + var instanceSizeAndAlignment = ComputeInstanceSize( + type, + cumulativeInstanceFieldPos + offsetBias, + largestAlignmentRequirement, + layoutMetadata.Size, + alignUpInstanceByteSize: true, + out instanceByteSizeAndAlignment); ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; @@ -704,7 +718,12 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, } SizeAndAlignment instanceByteSizeAndAlignment; - var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos + offsetBias, minAlign, 0/* specified field size unused */, out instanceByteSizeAndAlignment); + var instanceSizeAndAlignment = ComputeInstanceSize(type, + cumulativeInstanceFieldPos + offsetBias, + minAlign, + classLayoutSize: 0, + alignUpInstanceByteSize: true, + out instanceByteSizeAndAlignment); ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; @@ -829,7 +848,7 @@ private static int ComputePackingSize(MetadataType type, ClassLayoutMetadata lay return layoutMetadata.PackingSize; } - private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, int classLayoutSize, out SizeAndAlignment byteCount) + private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, int classLayoutSize, bool alignUpInstanceByteSize, out SizeAndAlignment byteCount) { SizeAndAlignment result; @@ -857,7 +876,9 @@ private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt { if (type.IsValueType) { - instanceSize = LayoutInt.AlignUp(instanceSize, alignment, target); + instanceSize = LayoutInt.AlignUp(instanceSize, + alignUpInstanceByteSize ? alignment : LayoutInt.Min(alignment, target.LayoutPointerSize), + target); } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index 1cc09466ee216..81e49b0e23f56 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -813,6 +813,8 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada } } + protected override bool IsBlittableOrManagedSequential(TypeDesc type) => MarshalUtils.IsBlittableType(type) || IsManagedSequentialType(type); + /// /// This method decides whether the type needs aligned base offset in order to have layout resilient to /// base class layout changes. diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 02fae7f99f2bb..06e0775f61daf 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -13543,7 +13543,7 @@ void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap) // - Alignment // - Position of GC references // -BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob) +BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob, BOOL printDiff) { STANDARD_VM_CONTRACT; @@ -13553,13 +13553,28 @@ BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob) uint32_t dwFlags; IfFailThrow(p.GetData(&dwFlags)); + BOOL result = TRUE; + // Size is checked unconditionally uint32_t dwExpectedSize; IfFailThrow(p.GetData(&dwExpectedSize)); DWORD dwActualSize = pMT->GetNumInstanceFieldBytes(); if (dwExpectedSize != dwActualSize) - return FALSE; + { + if (printDiff) + { + result = FALSE; + + DefineFullyQualifiedNameForClassW(); + wprintf(W("Type %s: expected size 0x%08x, actual size 0x%08x\n"), + GetFullyQualifiedNameForClassW(pMT), dwExpectedSize, dwActualSize); + } + else + { + return FALSE; + } + } #ifdef FEATURE_HFA if (dwFlags & READYTORUN_LAYOUT_HFA) @@ -13569,12 +13584,38 @@ BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob) DWORD dwActualHFAType = pMT->GetHFAType(); if (dwExpectedHFAType != dwActualHFAType) - return FALSE; + { + if (printDiff) + { + result = FALSE; + + DefineFullyQualifiedNameForClassW(); + wprintf(W("Type %s: expected HFA type %08x, actual %08x\n"), + GetFullyQualifiedNameForClassW(pMT), dwExpectedHFAType, dwActualHFAType); + } + else + { + return FALSE; + } + } } else { if (pMT->IsHFA()) - return FALSE; + { + if (printDiff) + { + result = FALSE; + + DefineFullyQualifiedNameForClassW(); + wprintf(W("Type %s: type is HFA but READYTORUN_LAYOUT_HFA flag is not set\n"), + GetFullyQualifiedNameForClassW(pMT)); + } + else + { + return FALSE; + } + } } #else _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA)); @@ -13590,7 +13631,20 @@ BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob) DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT); if (dwExpectedAlignment != dwActualAlignment) - return FALSE; + { + if (printDiff) + { + result = FALSE; + + DefineFullyQualifiedNameForClassW(); + wprintf(W("Type %s: expected alignment 0x%08x, actual 0x%08x\n"), + GetFullyQualifiedNameForClassW(pMT), dwExpectedAlignment, dwActualAlignment); + } + else + { + return FALSE; + } + } } @@ -13599,7 +13653,20 @@ BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob) if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty) { if (pMT->ContainsPointers()) - return FALSE; + { + if (printDiff) + { + result = FALSE; + + DefineFullyQualifiedNameForClassW(); + wprintf(W("Type %s contains pointers but READYTORUN_LAYOUT_GCLayout_Empty is set\n"), + GetFullyQualifiedNameForClassW(pMT)); + } + else + { + return FALSE; + } + } } else { @@ -13611,11 +13678,24 @@ BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob) ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap); if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0) - return FALSE; + { + if (printDiff) + { + result = FALSE; + + DefineFullyQualifiedNameForClassW(); + wprintf(W("Type %s: GC refmap content doesn't match\n"), + GetFullyQualifiedNameForClassW(pMT)); + } + else + { + return FALSE; + } + } } } - return TRUE; + return result; } #endif // FEATURE_READYTORUN @@ -14068,7 +14148,7 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, MethodTable * pMT = th.AsMethodTable(); _ASSERTE(pMT->IsValueType()); - if (!TypeLayoutCheck(pMT, pBlob)) + if (!TypeLayoutCheck(pMT, pBlob, /* printDiff */ kind == ENCODE_VERIFY_TYPE_LAYOUT)) { if (kind == ENCODE_CHECK_TYPE_LAYOUT) { @@ -14087,7 +14167,7 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, StackScratchBuffer buf; _ASSERTE_MSG(false, fatalErrorString.GetUTF8(buf)); // Run through the type layout logic again, after the assert, makes debugging easy - TypeLayoutCheck(pMT, pBlob); + TypeLayoutCheck(pMT, pBlob, /* printDiff */ TRUE); } #endif From 790f45f5aa49a99caa40f2183d0610ff4dd9e693 Mon Sep 17 00:00:00 2001 From: Tomas Date: Sun, 18 Apr 2021 22:08:58 +0200 Subject: [PATCH 02/16] One more fix for explicit layout with zero fields --- .../Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index c654283c16ab1..4e38ce4447438 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -317,7 +317,7 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty cumulativeInstanceFieldPos -= offsetBias; var layoutMetadata = type.GetClassLayout(); - LayoutInt instanceSize = cumulativeInstanceFieldPos + new LayoutInt(layoutMetadata.Size); + LayoutInt instanceSize = cumulativeInstanceFieldPos + new LayoutInt(layoutMetadata.Size) + offsetBias; int packingSize = ComputePackingSize(type, layoutMetadata); LayoutInt largestAlignmentRequired = LayoutInt.One; From e7678fd30d0f2dabafe876fca670197984f8a64b Mon Sep 17 00:00:00 2001 From: Tomas Date: Sat, 17 Apr 2021 20:49:02 +0200 Subject: [PATCH 03/16] Switch over the runtime outerloop pipeline to use Crossgen2 With this change, the only remaining pipelines using Crossgen1 are "r2r.yml", "r2r-extra.yml" and "release-tests.yml". I haven't yet identified the pipeline running the "release-tests.yml" script; for the "r2r*.yml", these now remain the only pipelines exercising Crossgen1. I don't think it makes sense to switch them over to CG2 as we already have their CG2 counterparts; my expectation is that, once CG1 is finally decommissioned, they will be just deleted. Thanks Tomas --- eng/pipelines/coreclr/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eng/pipelines/coreclr/ci.yml b/eng/pipelines/coreclr/ci.yml index d0d461e24c326..117f645186fb9 100644 --- a/eng/pipelines/coreclr/ci.yml +++ b/eng/pipelines/coreclr/ci.yml @@ -147,7 +147,8 @@ jobs: jobParameters: testGroup: outerloop readyToRun: true - displayNameArgs: R2R + crossgen2: true + displayNameArgs: R2R_CG2 liveLibrariesBuildConfig: Release # From a9aa8c3fc4db4498c1f86c0f03e33ddabbed3257 Mon Sep 17 00:00:00 2001 From: Tomas Date: Fri, 7 May 2021 14:13:20 +0200 Subject: [PATCH 04/16] Remove no longer needed R2RMFLA override of IsBlittableOrManagedSequential --- .../Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index 81e49b0e23f56..1cc09466ee216 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -813,8 +813,6 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada } } - protected override bool IsBlittableOrManagedSequential(TypeDesc type) => MarshalUtils.IsBlittableType(type) || IsManagedSequentialType(type); - /// /// This method decides whether the type needs aligned base offset in order to have layout resilient to /// base class layout changes. From 1e2abf3ea5ccc408f81a2b3e9919ca05ac0fb3fc Mon Sep 17 00:00:00 2001 From: Tomas Date: Fri, 28 May 2021 17:26:48 +0200 Subject: [PATCH 05/16] Implement IsBlittableOrManagedSequential using a R2R-specific override --- .../Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 2 +- .../Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 4e38ce4447438..993c3893d0418 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -305,7 +305,7 @@ protected virtual void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContex { } - protected virtual bool IsBlittableOrManagedSequential(TypeDesc type) => false; + protected virtual bool IsBlittableOrManagedSequential(TypeDesc type) => throw new NotImplementedException(); protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType type, int numInstanceFields) { diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index 1cc09466ee216..b575e6ab58bb7 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -827,6 +827,11 @@ protected override void AlignBaseOffsetIfNecessary(MetadataType type, ref Layout } } + protected override bool IsBlittableOrManagedSequential(TypeDesc type) + { + return MarshalUtils.IsBlittableType(type) || IsManagedSequentialType(type); + } + public static bool IsManagedSequentialType(TypeDesc type) { if (type.IsPointer) From d21272eda2066c72869753b23d25b70d9375a30a Mon Sep 17 00:00:00 2001 From: Tomas Date: Fri, 28 May 2021 19:22:45 +0200 Subject: [PATCH 06/16] Rename the method per JanK's PR feedback --- .../Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 4 ++-- .../Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 993c3893d0418..e3babfe588b24 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -305,7 +305,7 @@ protected virtual void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContex { } - protected virtual bool IsBlittableOrManagedSequential(TypeDesc type) => throw new NotImplementedException(); + protected virtual bool AlignUpInstanceByteSizeForExplicitFieldLayoutCompatQuirk(TypeDesc type) => true; protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType type, int numInstanceFields) { @@ -373,7 +373,7 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty instanceSize, largestAlignmentRequired, layoutMetadata.Size, - alignUpInstanceByteSize: IsBlittableOrManagedSequential(type), + alignUpInstanceByteSize: AlignUpInstanceByteSizeForExplicitFieldLayoutCompatQuirk(type), out instanceByteSizeAndAlignment); ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index b575e6ab58bb7..76e237cec5c1c 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -827,7 +827,7 @@ protected override void AlignBaseOffsetIfNecessary(MetadataType type, ref Layout } } - protected override bool IsBlittableOrManagedSequential(TypeDesc type) + protected override bool AlignUpInstanceByteSizeForExplicitFieldLayoutCompatQuirk(TypeDesc type) { return MarshalUtils.IsBlittableType(type) || IsManagedSequentialType(type); } From a9549d42d9d034295c82325559f52afeb7b7c7ba Mon Sep 17 00:00:00 2001 From: Tomas Date: Tue, 1 Jun 2021 20:56:09 +0200 Subject: [PATCH 07/16] Fix two explicit layout details 1) Mimic CoreCLR runtime bug filed under #53542; 2) Fix pointer alignment for byref-like fields. --- .../Common/MetadataFieldLayoutAlgorithm.cs | 15 ++++++++++++--- .../InstanceFieldLayoutTests.cs | 6 +++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index e3babfe588b24..ec20600daadcd 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -312,9 +312,17 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty // 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 offsetBias = !type.IsValueType ? new LayoutInt(type.Context.Target.PointerSize) : LayoutInt.Zero; - LayoutInt cumulativeInstanceFieldPos = - type.HasBaseType && !type.IsValueType ? type.BaseType.InstanceByteCount : LayoutInt.Zero; - cumulativeInstanceFieldPos -= offsetBias; + LayoutInt cumulativeInstanceFieldPos = CalculateFieldBaseOffset(type, requiresAlign8: false, requiresAlignedBase: false) - offsetBias; + if (!type.IsValueType) + { + // CoreCLR runtime has a bug in field offset calculation in the presence of class inheritance + // and explicit layout: in classlayoutinfo.cpp, the calculated layout adds base class size to + // field offsets (so that they are instance-relative) but HandleExplicitLayout in methodtablebuilder + // treats them as relative to the 'instance slice' which is offset by the base class size once more, + // effectively doubling the base class offset. + cumulativeInstanceFieldPos = cumulativeInstanceFieldPos + cumulativeInstanceFieldPos; + } + LayoutInt instanceSize = cumulativeInstanceFieldPos + offsetBias; var layoutMetadata = type.GetClassLayout(); LayoutInt instanceSize = cumulativeInstanceFieldPos + new LayoutInt(layoutMetadata.Size) + offsetBias; @@ -352,6 +360,7 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty ); if (needsToBeAligned) { + // ByRefLike types aren't guaranteed to have pointer alignment by themselves largestAlignmentRequired = LayoutInt.Max(largestAlignmentRequired, type.Context.Target.LayoutPointerSize); int offsetModulo = computedOffset.AsInt % type.Context.Target.PointerSize; if (offsetModulo != 0) diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs index 942021d77bfa1..ae76cae9bbeea 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs @@ -86,7 +86,7 @@ public void TestExplicitTypeLayoutWithInheritance() // Class1 has size 24 which Class2 inherits from. Class2 adds a byte at offset 20, so + 21 // = 45, rounding up to the next pointer size = 48 - Assert.Equal(48, class2Type.InstanceByteCount.AsInt); + Assert.Equal(56, class2Type.InstanceByteCount.AsInt); foreach (var f in class2Type.GetFields()) { @@ -97,12 +97,12 @@ public void TestExplicitTypeLayoutWithInheritance() { // First field after base class, with offset 0 so it should lie on the byte count of // the base class = 24 - Assert.Equal(24, f.Offset.AsInt); + Assert.Equal(32, f.Offset.AsInt); } else if (f.Name == "Omg") { // Offset 20 from base class byte count = 44 - Assert.Equal(44, f.Offset.AsInt); + Assert.Equal(52, f.Offset.AsInt); } else { From c83c6f0cdaebde3d4cdf401b35f7d6d35d263565 Mon Sep 17 00:00:00 2001 From: Tomas Date: Tue, 1 Jun 2021 21:49:19 +0200 Subject: [PATCH 08/16] Fix bad conflict merge --- .../Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index ec20600daadcd..d4829fd0cee40 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -325,8 +325,6 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty LayoutInt instanceSize = cumulativeInstanceFieldPos + offsetBias; var layoutMetadata = type.GetClassLayout(); - LayoutInt instanceSize = cumulativeInstanceFieldPos + new LayoutInt(layoutMetadata.Size) + offsetBias; - int packingSize = ComputePackingSize(type, layoutMetadata); LayoutInt largestAlignmentRequired = LayoutInt.One; From a50d93fef06c6e68b0c2623c37edbdb8e4283458 Mon Sep 17 00:00:00 2001 From: Tomas Date: Wed, 2 Jun 2021 01:32:21 +0200 Subject: [PATCH 09/16] Mark remaining CG2 outerloop failures to clean up the CI results --- src/tests/issues.targets | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 5fb3ed14c4c23..a0c0e0ccd43fd 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -349,6 +349,12 @@ https://github.com/dotnet/runtime/issues/8034 The test causes OutOfMemory exception in crossgen mode. + + https://github.com/dotnet/runtime/issues/53559 + + + https://github.com/dotnet/runtime/issues/53559 + Varargs supported on this platform @@ -566,12 +572,21 @@ https://github.com/dotnet/runtime/issues/12979 + + https://github.com/dotnet/runtime/issues/53560 + https://github.com/dotnet/runtime/issues/12979 https://github.com/dotnet/runtime/issues/12979 + + https://github.com/dotnet/runtime/issues/53561 + + + https://github.com/dotnet/runtime/issues/53561 + From a4e3aeecc5033235b797ece3792bab091e74debb Mon Sep 17 00:00:00 2001 From: Tomas Date: Wed, 2 Jun 2021 01:36:07 +0200 Subject: [PATCH 10/16] Remove artificial alignment change per DavidWr's PR feedback --- .../Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index d4829fd0cee40..46848e409e284 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -358,8 +358,6 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty ); if (needsToBeAligned) { - // ByRefLike types aren't guaranteed to have pointer alignment by themselves - largestAlignmentRequired = LayoutInt.Max(largestAlignmentRequired, type.Context.Target.LayoutPointerSize); int offsetModulo = computedOffset.AsInt % type.Context.Target.PointerSize; if (offsetModulo != 0) { From 54e4dd489445da8db8169b284c335b2c02f7131a Mon Sep 17 00:00:00 2001 From: Tomas Date: Wed, 2 Jun 2021 17:19:00 +0200 Subject: [PATCH 11/16] Fix the StructPacking test on ARM --- .../Common/MetadataFieldLayoutAlgorithm.cs | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 46848e409e284..c49804fbfb09e 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -229,7 +229,7 @@ public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defTy } ref StaticsBlock block = ref GetStaticsBlockForField(ref result, field); - SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, context.Target.DefaultPackingSize, out bool _); + SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout: false, context.Target.DefaultPackingSize, out bool _); block.Size = LayoutInt.AlignUp(block.Size, sizeAndAlignment.Alignment, context.Target); result.Offsets[index] = new FieldAndOffset(field, block.Size); @@ -335,7 +335,7 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty foreach (var fieldAndOffset in layoutMetadata.Offsets) { TypeDesc fieldType = fieldAndOffset.Field.FieldType; - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, packingSize, out bool fieldLayoutAbiStable); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable); if (!fieldLayoutAbiStable) layoutAbiStable = false; @@ -421,7 +421,7 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType if (field.IsStatic) continue; - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, packingSize, out bool fieldLayoutAbiStable); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable); if (!fieldLayoutAbiStable) layoutAbiStable = false; @@ -462,6 +462,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, { TypeSystemContext context = type.Context; + bool hasLayout = type.HasLayout(); var layoutMetadata = type.GetClassLayout(); int packingSize = ComputePackingSize(type, layoutMetadata); @@ -497,7 +498,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, { Debug.Assert(fieldType.IsPrimitive || fieldType.IsPointer || fieldType.IsFunctionPointer || fieldType.IsEnum); - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, packingSize, out bool _); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout, packingSize, out bool _); instanceNonGCPointerFieldsCount[CalculateLog2(fieldSizeAndAlignment.Size.AsInt)]++; } } @@ -534,7 +535,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, TypeDesc fieldType = field.FieldType; - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, packingSize, out bool fieldLayoutAbiStable); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout, packingSize, out bool fieldLayoutAbiStable); if (!fieldLayoutAbiStable) layoutAbiStable = false; @@ -641,7 +642,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, // Place the field j = instanceNonGCPointerFieldsCount[i]; FieldDesc field = instanceNonGCPointerFieldsArr[i][j]; - PlaceInstanceField(field, packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal, offsetBias); + PlaceInstanceField(field, hasLayout, packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal, offsetBias); instanceNonGCPointerFieldsCount[i]++; } @@ -658,14 +659,14 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, { for (int j = 0; j < instanceGCPointerFieldsArr.Length; j++) { - PlaceInstanceField(instanceGCPointerFieldsArr[j], packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal, offsetBias); + PlaceInstanceField(instanceGCPointerFieldsArr[j], hasLayout, packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal, offsetBias); } } // The start index will be the index that may have been increased in the previous optimization for (int j = instanceNonGCPointerFieldsCount[i]; j < instanceNonGCPointerFieldsArr[i].Length; j++) { - PlaceInstanceField(instanceNonGCPointerFieldsArr[i][j], packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal, offsetBias); + PlaceInstanceField(instanceNonGCPointerFieldsArr[i][j], hasLayout, packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal, offsetBias); } } @@ -675,7 +676,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, // If the field has an indeterminate alignment, align the cumulative field offset to the indeterminate value // Otherwise, align the cumulative field offset to the PointerSize // This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(instanceValueClassFieldsArr[i].FieldType, packingSize, out bool fieldLayoutAbiStable); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(instanceValueClassFieldsArr[i].FieldType, hasLayout, packingSize, out bool fieldLayoutAbiStable); if (!fieldLayoutAbiStable) layoutAbiStable = false; @@ -741,9 +742,9 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, return computedLayout; } - private static void PlaceInstanceField(FieldDesc field, int packingSize, FieldAndOffset[] offsets, ref LayoutInt instanceFieldPos, ref int fieldOrdinal, LayoutInt offsetBias) + private static void PlaceInstanceField(FieldDesc field, bool hasLayout, int packingSize, FieldAndOffset[] offsets, ref LayoutInt instanceFieldPos, ref int fieldOrdinal, LayoutInt offsetBias) { - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, packingSize, out bool _); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, hasLayout, packingSize, out bool _); instanceFieldPos = AlignUpInstanceFieldOffset(field.OwningType, instanceFieldPos, fieldSizeAndAlignment.Alignment, field.Context.Target); offsets[fieldOrdinal] = new FieldAndOffset(field, instanceFieldPos + offsetBias); @@ -804,7 +805,7 @@ public LayoutInt CalculateFieldBaseOffset(MetadataType type, bool requiresAlign8 return cumulativeInstanceFieldPos; } - private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, int packingSize, out bool layoutAbiStable) + private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, bool hasLayout, int packingSize, out bool layoutAbiStable) { SizeAndAlignment result; layoutAbiStable = true; @@ -839,7 +840,10 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, result.Alignment = fieldType.Context.Target.LayoutPointerSize; } - result.Alignment = LayoutInt.Min(result.Alignment, new LayoutInt(packingSize)); + if (hasLayout) + { + result.Alignment = LayoutInt.Min(result.Alignment, new LayoutInt(packingSize)); + } return result; } From 3dcdc3190708539efc91168fc6f0e3389a1aefe9 Mon Sep 17 00:00:00 2001 From: Tomas Date: Wed, 2 Jun 2021 22:00:32 +0200 Subject: [PATCH 12/16] Improve fix for StructPacking, finally fix 46239 on ARM --- .../TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index c49804fbfb09e..069feab7e04c4 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -840,18 +840,21 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, result.Alignment = fieldType.Context.Target.LayoutPointerSize; } - if (hasLayout) + if (fieldType.Context.Target.Architecture != TargetArchitecture.ARM) { result.Alignment = LayoutInt.Min(result.Alignment, new LayoutInt(packingSize)); } + else if (packingSize < 8) + { + result.Alignment = LayoutInt.Min(result.Alignment, fieldType.Context.Target.LayoutPointerSize); + } return result; } private static int ComputePackingSize(MetadataType type, ClassLayoutMetadata layoutMetadata) { - // If a type contains pointers then the metadata specified packing size is ignored (On .NET Framework this is disqualification from ManagedSequential) - if (layoutMetadata.PackingSize == 0 || type.ContainsGCPointers) + if (layoutMetadata.PackingSize == 0) return type.Context.Target.DefaultPackingSize; else return layoutMetadata.PackingSize; From cabf41ca935c15bc44d4023ec1d22c193e1a8076 Mon Sep 17 00:00:00 2001 From: Tomas Date: Thu, 3 Jun 2021 01:48:17 +0200 Subject: [PATCH 13/16] Further refining of the ARM case --- .../Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 069feab7e04c4..86f27b65cd439 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -840,7 +840,7 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, result.Alignment = fieldType.Context.Target.LayoutPointerSize; } - if (fieldType.Context.Target.Architecture != TargetArchitecture.ARM) + if (!hasLayout || fieldType.Context.Target.Architecture != TargetArchitecture.ARM) { result.Alignment = LayoutInt.Min(result.Alignment, new LayoutInt(packingSize)); } From 642659b3b2f50085b9de83c72bd74eb401cb783d Mon Sep 17 00:00:00 2001 From: Tomas Date: Thu, 3 Jun 2021 14:36:49 +0200 Subject: [PATCH 14/16] Fix subtle difference in x86 alignment with vs. without layout --- .../TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 86f27b65cd439..90b347a8ef218 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -840,13 +840,13 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, result.Alignment = fieldType.Context.Target.LayoutPointerSize; } - if (!hasLayout || fieldType.Context.Target.Architecture != TargetArchitecture.ARM) + if (hasLayout) { result.Alignment = LayoutInt.Min(result.Alignment, new LayoutInt(packingSize)); } - else if (packingSize < 8) + else { - result.Alignment = LayoutInt.Min(result.Alignment, fieldType.Context.Target.LayoutPointerSize); + result.Alignment = LayoutInt.Min(result.Alignment, fieldType.Context.Target.GetObjectAlignment(result.Alignment)); } return result; From f14893c8047b7fafc7c6cc4ea21f54070c932911 Mon Sep 17 00:00:00 2001 From: Tomas Date: Thu, 3 Jun 2021 20:00:09 +0200 Subject: [PATCH 15/16] Remove the duplicate base type size quirk per JanK's PR feedback --- .../TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 90b347a8ef218..2bf40935a38b6 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -313,15 +313,6 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty // It is calculated as the field whose offset and size add to the greatest value. LayoutInt offsetBias = !type.IsValueType ? new LayoutInt(type.Context.Target.PointerSize) : LayoutInt.Zero; LayoutInt cumulativeInstanceFieldPos = CalculateFieldBaseOffset(type, requiresAlign8: false, requiresAlignedBase: false) - offsetBias; - if (!type.IsValueType) - { - // CoreCLR runtime has a bug in field offset calculation in the presence of class inheritance - // and explicit layout: in classlayoutinfo.cpp, the calculated layout adds base class size to - // field offsets (so that they are instance-relative) but HandleExplicitLayout in methodtablebuilder - // treats them as relative to the 'instance slice' which is offset by the base class size once more, - // effectively doubling the base class offset. - cumulativeInstanceFieldPos = cumulativeInstanceFieldPos + cumulativeInstanceFieldPos; - } LayoutInt instanceSize = cumulativeInstanceFieldPos + offsetBias; var layoutMetadata = type.GetClassLayout(); From c5ac961de2d7b4db425d7a961fe6e0e81e8a8040 Mon Sep 17 00:00:00 2001 From: Tomas Date: Thu, 3 Jun 2021 23:57:41 +0200 Subject: [PATCH 16/16] Update the typesystem unit tests to removal of the base size quirk --- .../InstanceFieldLayoutTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs index ae76cae9bbeea..03b5b160fdaf8 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs @@ -86,7 +86,7 @@ public void TestExplicitTypeLayoutWithInheritance() // Class1 has size 24 which Class2 inherits from. Class2 adds a byte at offset 20, so + 21 // = 45, rounding up to the next pointer size = 48 - Assert.Equal(56, class2Type.InstanceByteCount.AsInt); + Assert.Equal(48, class2Type.InstanceByteCount.AsInt); foreach (var f in class2Type.GetFields()) { @@ -97,12 +97,12 @@ public void TestExplicitTypeLayoutWithInheritance() { // First field after base class, with offset 0 so it should lie on the byte count of // the base class = 24 - Assert.Equal(32, f.Offset.AsInt); + Assert.Equal(20, f.Offset.AsInt); } else if (f.Name == "Omg") { // Offset 20 from base class byte count = 44 - Assert.Equal(52, f.Offset.AsInt); + Assert.Equal(40, f.Offset.AsInt); } else {