diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
index 1f57b5f1a8c4b2..f7372ba0d6edd9 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
@@ -308,9 +308,11 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata
{
// 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();
@@ -333,7 +335,7 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata
if (fieldAndOffset.Offset == FieldAndOffset.InvalidOffset)
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
- LayoutInt computedOffset = fieldAndOffset.Offset + cumulativeInstanceFieldPos;
+ LayoutInt computedOffset = fieldAndOffset.Offset + cumulativeInstanceFieldPos + offsetBias;
// GC pointers MUST be aligned.
// We treat byref-like structs as GC pointers too.
@@ -379,29 +381,20 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata
return computedLayout;
}
- private static LayoutInt AlignUpInstanceFieldOffset(TypeDesc typeWithField, LayoutInt cumulativeInstanceFieldPos, LayoutInt alignment, TargetDetails target, bool armAlignFromStartOfFields = false)
+ private static LayoutInt AlignUpInstanceFieldOffset(TypeDesc typeWithField, LayoutInt cumulativeInstanceFieldPos, LayoutInt alignment, TargetDetails target)
{
- if (!typeWithField.IsValueType && (target.Architecture == TargetArchitecture.X86 || (armAlignFromStartOfFields && target.Architecture == TargetArchitecture.ARM)) && cumulativeInstanceFieldPos != new LayoutInt(0))
- {
- // Alignment of fields is relative to the start of the field list, not the start of the object
- //
- // The code in the VM is written as if this is the rule for all architectures, but for ARM 32bit platforms
- // there is an additional adjustment via dwOffsetBias that aligns fields based on the start of the object
- cumulativeInstanceFieldPos = cumulativeInstanceFieldPos - new LayoutInt(target.PointerSize);
- return LayoutInt.AlignUp(cumulativeInstanceFieldPos, alignment, target) + new LayoutInt(target.PointerSize);
- }
- else
- {
- return LayoutInt.AlignUp(cumulativeInstanceFieldPos, alignment, target);
- }
+ return LayoutInt.AlignUp(cumulativeInstanceFieldPos, alignment, target);
}
- protected static ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType type, int numInstanceFields)
+ protected 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);
+ // For reference types, we calculate field alignment as if the address after the method table pointer
+ // has offset 0 (on 32-bit platforms, this location is guaranteed to be 8-aligned).
+ LayoutInt offsetBias = !type.IsValueType ? new LayoutInt(type.Context.Target.PointerSize) : LayoutInt.Zero;
+ LayoutInt cumulativeInstanceFieldPos = CalculateFieldBaseOffset(type, requiresAlign8: false, requiresAlignedBase: false) - offsetBias;
var layoutMetadata = type.GetClassLayout();
@@ -421,18 +414,15 @@ protected static ComputedInstanceFieldLayout ComputeSequentialFieldLayout(Metada
largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement);
- cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, type.Context.Target,
- armAlignFromStartOfFields: true // In what appears to have been a bug in the design of the arm32 type layout code
- // this portion of the layout algorithm does not layout from the start of the object
- );
- offsets[fieldOrdinal] = new FieldAndOffset(field, cumulativeInstanceFieldPos);
+ cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, type.Context.Target);
+ offsets[fieldOrdinal] = new FieldAndOffset(field, cumulativeInstanceFieldPos + offsetBias);
cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + fieldSizeAndAlignment.Size);
fieldOrdinal++;
}
SizeAndAlignment instanceByteSizeAndAlignment;
- var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, largestAlignmentRequirement, layoutMetadata.Size, out instanceByteSizeAndAlignment);
+ var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos + offsetBias, largestAlignmentRequirement, layoutMetadata.Size, out instanceByteSizeAndAlignment);
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
@@ -445,14 +435,12 @@ protected static ComputedInstanceFieldLayout ComputeSequentialFieldLayout(Metada
return computedLayout;
}
- protected virtual void AlignBaseOffsetIfNecessary(MetadataType type, ref LayoutInt baseOffset, bool requiresAlign8)
+ protected virtual void AlignBaseOffsetIfNecessary(MetadataType type, ref LayoutInt baseOffset, bool requiresAlign8, bool requiresAlignedBase)
{
}
protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, int numInstanceFields)
{
- // For types inheriting from another type, field offsets continue on from where they left off
- LayoutInt cumulativeInstanceFieldPos = ComputeBytesUsedInParentType(type);
TypeSystemContext context = type.Context;
var layoutMetadata = type.GetClassLayout();
@@ -463,7 +451,6 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
var offsets = new FieldAndOffset[numInstanceFields];
int fieldOrdinal = 0;
-
// Iterate over the instance fields and keep track of the number of fields of each category
// For the non-GC Pointer fields, we will keep track of the number of fields by log2(size)
int maxLog2Size = CalculateLog2(TargetDetails.MaximumPrimitiveSize);
@@ -552,18 +539,15 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
largestAlignmentRequired = context.Target.GetObjectAlignment(largestAlignmentRequired);
bool requiresAlign8 = !largestAlignmentRequired.IsIndeterminate && largestAlignmentRequired.AsInt > 4;
- if (!type.IsValueType)
+ // For types inheriting from another type, field offsets continue on from where they left off
+ // Base alignment is not always required, it's only applied when there's a version bubble boundary
+ // 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)
{
- DefType baseType = type.BaseType;
- if (baseType != null && !baseType.IsObject)
- {
- if (!requiresAlign8 && baseType.RequiresAlign8())
- {
- requiresAlign8 = true;
- }
-
- AlignBaseOffsetIfNecessary(type, ref cumulativeInstanceFieldPos, requiresAlign8);
- }
+ offsetBias = new LayoutInt(type.Context.Target.PointerSize);
+ cumulativeInstanceFieldPos -= offsetBias;
}
// We've finished placing the fields into their appropriate arrays
@@ -638,7 +622,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);
+ PlaceInstanceField(field, packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal, offsetBias);
instanceNonGCPointerFieldsCount[i]++;
}
@@ -655,14 +639,14 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
{
for (int j = 0; j < instanceGCPointerFieldsArr.Length; j++)
{
- PlaceInstanceField(instanceGCPointerFieldsArr[j], packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal);
+ PlaceInstanceField(instanceGCPointerFieldsArr[j], 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);
+ PlaceInstanceField(instanceNonGCPointerFieldsArr[i][j], packingSize, offsets, ref cumulativeInstanceFieldPos, ref fieldOrdinal, offsetBias);
}
}
@@ -685,7 +669,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
LayoutInt AlignmentRequired = LayoutInt.Max(fieldSizeAndAlignment.Alignment, context.Target.LayoutPointerSize);
cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, AlignmentRequired, context.Target);
}
- offsets[fieldOrdinal] = new FieldAndOffset(instanceValueClassFieldsArr[i], cumulativeInstanceFieldPos);
+ offsets[fieldOrdinal] = new FieldAndOffset(instanceValueClassFieldsArr[i], cumulativeInstanceFieldPos + offsetBias);
// If the field has an indeterminate size, align the cumulative field offset to the indeterminate value
// Otherwise, align the cumulative field offset to the aligned-instance field size
@@ -720,7 +704,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
}
SizeAndAlignment instanceByteSizeAndAlignment;
- var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos, minAlign, 0/* specified field size unused */, out instanceByteSizeAndAlignment);
+ var instanceSizeAndAlignment = ComputeInstanceSize(type, cumulativeInstanceFieldPos + offsetBias, minAlign, 0/* specified field size unused */, out instanceByteSizeAndAlignment);
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
@@ -733,12 +717,12 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
return computedLayout;
}
- private static void PlaceInstanceField(FieldDesc field, int packingSize, FieldAndOffset[] offsets, ref LayoutInt instanceFieldPos, ref int fieldOrdinal)
+ private static void PlaceInstanceField(FieldDesc field, int packingSize, FieldAndOffset[] offsets, ref LayoutInt instanceFieldPos, ref int fieldOrdinal, LayoutInt offsetBias)
{
var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, packingSize, out bool _);
instanceFieldPos = AlignUpInstanceFieldOffset(field.OwningType, instanceFieldPos, fieldSizeAndAlignment.Alignment, field.Context.Target);
- offsets[fieldOrdinal] = new FieldAndOffset(field, instanceFieldPos);
+ offsets[fieldOrdinal] = new FieldAndOffset(field, instanceFieldPos + offsetBias);
instanceFieldPos = checked(instanceFieldPos + fieldSizeAndAlignment.Size);
fieldOrdinal++;
@@ -775,13 +759,22 @@ private static bool IsByValueClass(TypeDesc type)
return type.IsValueType && !type.IsPrimitive && !type.IsEnum;
}
- private static LayoutInt ComputeBytesUsedInParentType(DefType type)
+ public LayoutInt CalculateFieldBaseOffset(MetadataType type, bool requiresAlign8, bool requiresAlignedBase)
{
LayoutInt cumulativeInstanceFieldPos = LayoutInt.Zero;
if (!type.IsValueType && type.HasBaseType)
{
cumulativeInstanceFieldPos = type.BaseType.InstanceByteCountUnaligned;
+ if (!type.BaseType.InstanceByteCountUnaligned.IsIndeterminate)
+ {
+ cumulativeInstanceFieldPos = type.BaseType.InstanceByteCountUnaligned;
+ if (type.BaseType.IsZeroSizedReferenceType && ((MetadataType)type.BaseType).HasLayout())
+ {
+ cumulativeInstanceFieldPos += LayoutInt.One;
+ }
+ AlignBaseOffsetIfNecessary(type, ref cumulativeInstanceFieldPos, requiresAlign8, requiresAlignedBase);
+ }
}
return cumulativeInstanceFieldPos;
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CompilationModuleGroup.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CompilationModuleGroup.ReadyToRun.cs
index 2312ecc1c4a755..e2ec6059d5dc77 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CompilationModuleGroup.ReadyToRun.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CompilationModuleGroup.ReadyToRun.cs
@@ -81,6 +81,12 @@ public bool EnforceOwningType(EcmaModule module)
///
public abstract bool IsInputBubble { get; }
+ ///
+ /// Returns true when the base type and derived type don't reside in the same version bubble
+ /// in which case the runtime aligns the field base offset.
+ ///
+ public abstract bool NeedsAlignmentBetweenBaseTypeAndDerived(MetadataType baseType, MetadataType derivedType);
+
///
/// List of input modules to use for the compilation.
///
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs
index 62b5f5ce8c18ed..f993b381d8ceae 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs
@@ -41,22 +41,31 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
EcmaModule targetModule = factory.SignatureContext.GetTargetModule(_fieldDesc);
SignatureContext innerContext = dataBuilder.EmitFixup(factory, _fixupKind, targetModule, factory.SignatureContext);
+ uint baseOffset = 0;
+ uint fieldOffset = (uint)_fieldDesc.Offset.AsInt;
if (_fixupKind == ReadyToRunFixupKind.Verify_FieldOffset)
{
TypeDesc baseType = _fieldDesc.OwningType.BaseType;
- if ((_fieldDesc.OwningType.BaseType != null) && !_fieldDesc.IsStatic && !_fieldDesc.OwningType.IsValueType)
+ if ((_fieldDesc.OwningType.BaseType != null)
+ && !_fieldDesc.IsStatic
+ && !_fieldDesc.OwningType.IsValueType)
{
- dataBuilder.EmitUInt((uint)_fieldDesc.OwningType.FieldBaseOffset().AsInt);
+ MetadataType owningType = (MetadataType)_fieldDesc.OwningType;
+ baseOffset = (uint)owningType.FieldBaseOffset().AsInt;
+ if (factory.CompilationModuleGroup.NeedsAlignmentBetweenBaseTypeAndDerived((MetadataType)baseType, owningType))
+ {
+ fieldOffset -= baseOffset;
+ baseOffset = 0;
+ }
}
- else
- dataBuilder.EmitUInt(0);
+ dataBuilder.EmitUInt(baseOffset);
}
if ((_fixupKind == ReadyToRunFixupKind.Check_FieldOffset) ||
(_fixupKind == ReadyToRunFixupKind.Verify_FieldOffset))
{
- dataBuilder.EmitUInt((uint)_fieldDesc.Offset.AsInt);
+ dataBuilder.EmitUInt(fieldOffset);
}
dataBuilder.EmitFieldSignature(_fieldDesc, innerContext);
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs
index 2e0a760e9725a3..92ef5346c770fd 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs
@@ -267,8 +267,11 @@ private bool ModuleMatchesCompilationUnitIndex(ModuleDesc module1, ModuleDesc mo
return ModuleToCompilationUnitIndex(module1) == ModuleToCompilationUnitIndex(module2);
}
- public bool NeedsAlignmentBetweenBaseTypeAndDerived(MetadataType baseType, MetadataType derivedType)
+ public override bool NeedsAlignmentBetweenBaseTypeAndDerived(MetadataType baseType, MetadataType derivedType)
{
+ if (baseType.IsObject)
+ return false;
+
if (!ModuleMatchesCompilationUnitIndex(derivedType.Module, baseType.Module) ||
TypeLayoutCompilationUnits(baseType).HasMultipleCompilationUnits)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs
index 5b8c09852f7ec3..4c8f9770332ca7 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs
@@ -68,6 +68,13 @@ public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type)
}
}
+ ///
+ /// This is a rough equivalent of the CoreCLR runtime method ReadyToRunInfo::GetFieldBaseOffset.
+ /// In contrast to the auto field layout algorithm, this method unconditionally applies alignment
+ /// between base and derived class (even when they reside in the same version bubble).
+ ///
+ public LayoutInt CalculateFieldBaseOffset(MetadataType type) => _r2rFieldLayoutAlgorithm.CalculateFieldBaseOffset(type, type.RequiresAlign8(), requiresAlignedBase: true);
+
public void SetCompilationGroup(ReadyToRunCompilationModuleGroupBase compilationModuleGroup)
{
_r2rFieldLayoutAlgorithm.SetCompilationGroup(compilationModuleGroup);
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs
index be653fdcab1cdf..1cc09466ee216e 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs
@@ -18,15 +18,9 @@ namespace ILCompiler
{
public static class ReadyToRunTypeExtensions
{
- public static LayoutInt FieldBaseOffset(this TypeDesc type)
+ public static LayoutInt FieldBaseOffset(this MetadataType type)
{
- LayoutInt baseOffset = type.BaseType.InstanceByteCount;
- if (type.RequiresAlign8())
- {
- baseOffset = LayoutInt.AlignUp(baseOffset, new LayoutInt(8), type.Context.Target);
- }
-
- return baseOffset;
+ return ((ReadyToRunCompilerContext)type.Context).CalculateFieldBaseOffset(type);
}
}
@@ -823,23 +817,14 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada
/// This method decides whether the type needs aligned base offset in order to have layout resilient to
/// base class layout changes.
///
- protected override void AlignBaseOffsetIfNecessary(MetadataType type, ref LayoutInt baseOffset, bool requiresAlign8)
+ protected override void AlignBaseOffsetIfNecessary(MetadataType type, ref LayoutInt baseOffset, bool requiresAlign8, bool requiresAlignedBase)
{
- DefType baseType = type.BaseType;
-
- if (!_compilationGroup.NeedsAlignmentBetweenBaseTypeAndDerived(baseType: (MetadataType)baseType, derivedType: type))
- {
- // The type is defined in the module that's currently being compiled and the type layout doesn't depend on other modules
- return;
- }
-
- LayoutInt alignment = new LayoutInt(type.Context.Target.PointerSize);
-
- if (requiresAlign8)
+ if (requiresAlignedBase || _compilationGroup.NeedsAlignmentBetweenBaseTypeAndDerived(baseType: (MetadataType)type.BaseType, derivedType: type))
{
- alignment = new LayoutInt(8);
+ bool use8Align = (requiresAlign8 || type.BaseType.RequiresAlign8()) && type.Context.Target.Architecture != TargetArchitecture.X86;
+ LayoutInt alignment = new LayoutInt(use8Align ? 8 : type.Context.Target.PointerSize);
+ baseOffset = LayoutInt.AlignUp(baseOffset, alignment, type.Context.Target);
}
- baseOffset = LayoutInt.AlignUp(baseOffset, alignment, type.Context.Target);
}
public static bool IsManagedSequentialType(TypeDesc type)
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
index cd262716689e60..56a3cce130244e 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
@@ -2336,7 +2336,7 @@ private void EncodeFieldBaseOffset(FieldDesc field, CORINFO_FIELD_INFO* pResult,
}
// ENCODE_FIELD_BASE_OFFSET
- int fieldBaseOffset = pMT.FieldBaseOffset().AsInt;
+ int fieldBaseOffset = ((MetadataType)pMT).FieldBaseOffset().AsInt;
Debug.Assert(pResult->offset >= (uint)fieldBaseOffset);
pResult->offset -= (uint)fieldBaseOffset;
pResult->fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INSTANCE_WITH_BASE;
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 2a3b251ec5621e..2423c4887d61e5 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -14107,6 +14107,14 @@ BOOL LoadDynamicInfoEntry(Module *currentModule,
actualBaseOffset = ReadyToRunInfo::GetFieldBaseOffset(pEnclosingMT);
}
+ if (baseOffset == 0)
+ {
+ // Relative verification of just the field offset when the base class
+ // is outside of the current R2R version bubble
+ actualFieldOffset -= actualBaseOffset;
+ actualBaseOffset = 0;
+ }
+
if ((fieldOffset != actualFieldOffset) || (baseOffset != actualBaseOffset))
{
// Verification failures are failfast events
diff --git a/src/tests/Regressions/coreclr/GitHub_49982/test49982.cs b/src/tests/Regressions/coreclr/GitHub_49982/test49982.cs
new file mode 100644
index 00000000000000..ec3ae4343df4ce
--- /dev/null
+++ b/src/tests/Regressions/coreclr/GitHub_49982/test49982.cs
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+class Program
+{
+ private class MockEndPoint : EndPoint
+ {
+ }
+
+ private sealed class ExtendedSocketException : SocketException
+ {
+ private readonly EndPoint? _endPoint;
+
+ public ExtendedSocketException(EndPoint? endPoint)
+ : base(0)
+ {
+ _endPoint = endPoint;
+ }
+
+ public bool EndPointEquals(EndPoint? endPoint)
+ {
+ return _endPoint == endPoint;
+ }
+ }
+
+ static bool TestExtendedSocketException()
+ {
+ EndPoint endPoint = new MockEndPoint();
+ ExtendedSocketException extendedSocketException = new ExtendedSocketException(endPoint);
+ Console.WriteLine("ExtendedSocketException: {0}", extendedSocketException.GetType());
+ return extendedSocketException.EndPointEquals(endPoint);
+ }
+
+ static int Main()
+ {
+ Console.WriteLine("Extended socket exception:");
+ return TestExtendedSocketException() ? 100 : 1;
+ }
+}
diff --git a/src/tests/Regressions/coreclr/GitHub_49982/test49982.csproj b/src/tests/Regressions/coreclr/GitHub_49982/test49982.csproj
new file mode 100644
index 00000000000000..27de21752249f1
--- /dev/null
+++ b/src/tests/Regressions/coreclr/GitHub_49982/test49982.csproj
@@ -0,0 +1,19 @@
+
+
+ Exe
+ BuildAndRun
+ 1
+ enable
+ 9.0
+ true
+
+
+ true
+
+
+
+
+
+
+
+