Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix regression test 46239 with Crossgen2 and improve runtime logging #51416

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
3 changes: 2 additions & 1 deletion eng/pipelines/coreclr/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ jobs:
jobParameters:
testGroup: outerloop
readyToRun: true
displayNameArgs: R2R
crossgen2: true
displayNameArgs: R2R_CG2
liveLibrariesBuildConfig: Release

#
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/inc/readytorun.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
#define READYTORUN_SIGNATURE 0x00525452 // 'RTR'

// Keep these in sync with src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs
#define READYTORUN_MAJOR_VERSION 0x0005
#define READYTORUN_MINOR_VERSION 0x0003
#define READYTORUN_MAJOR_VERSION 0x0006
#define READYTORUN_MINOR_VERSION 0x0001

#define MINIMUM_READYTORUN_MAJOR_VERSION 0x003
#define MINIMUM_READYTORUN_MAJOR_VERSION 0x006

// R2R Version 2.1 adds the InliningInfo section
// R2R Version 2.2 adds the ProfileDataInfo section
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ internal struct ReadyToRunHeaderConstants
{
public const uint Signature = 0x00525452; // 'RTR'

public const ushort CurrentMajorVersion = 5;
public const ushort CurrentMinorVersion = 3;
public const ushort CurrentMajorVersion = 6;
public const ushort CurrentMinorVersion = 1;
}

#pragma warning disable 0169
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,13 +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;
LayoutInt offsetBias = (!type.IsValueType ? type.Context.Target.LayoutPointerSize : LayoutInt.Zero);
LayoutInt cumulativeInstanceFieldPos = (type.HasBaseType && !type.IsValueType ? type.BaseType.InstanceByteCount : LayoutInt.Zero) - offsetBias;

var layoutMetadata = type.GetClassLayout();
LayoutInt instanceSize = cumulativeInstanceFieldPos + new LayoutInt(layoutMetadata.Size) + offsetBias;

int packingSize = ComputePackingSize(type, layoutMetadata);
LayoutInt largestAlignmentRequired = LayoutInt.One;
Expand Down Expand Up @@ -349,6 +347,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)
{
Expand All @@ -365,7 +364,11 @@ 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,
out instanceByteSizeAndAlignment);

ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
Expand All @@ -375,7 +378,6 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata
computedLayout.Offsets = offsets;
computedLayout.LayoutAbiStable = layoutAbiStable;


ExplicitLayoutValidator.Validate(type, computedLayout);

return computedLayout;
Expand All @@ -393,7 +395,7 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType
// For types inheriting from another type, field offsets continue on from where they left off
// 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 offsetBias = (!type.IsValueType ? type.Context.Target.LayoutPointerSize : LayoutInt.Zero);
LayoutInt cumulativeInstanceFieldPos = CalculateFieldBaseOffset(type, requiresAlign8: false, requiresAlignedBase: false) - offsetBias;

var layoutMetadata = type.GetClassLayout();
Expand Down Expand Up @@ -422,7 +424,12 @@ 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,
out instanceByteSizeAndAlignment);

ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
Expand Down Expand Up @@ -546,7 +553,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
LayoutInt offsetBias = LayoutInt.Zero;
if (!type.IsValueType && cumulativeInstanceFieldPos != LayoutInt.Zero && type.Context.Target.Architecture == TargetArchitecture.X86)
{
offsetBias = new LayoutInt(type.Context.Target.PointerSize);
offsetBias = type.Context.Target.LayoutPointerSize;
cumulativeInstanceFieldPos -= offsetBias;
}

Expand Down Expand Up @@ -704,7 +711,11 @@ 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,
out instanceByteSizeAndAlignment);

ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout();
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
Expand Down Expand Up @@ -792,6 +803,10 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType,
DefType metadataType = (DefType)fieldType;
result.Size = metadataType.InstanceFieldSize;
result.Alignment = metadataType.InstanceFieldAlignment;
if (!fieldType.IsPrimitive && !fieldType.IsEnum)
{
result.Alignment = LayoutInt.Min(metadataType.InstanceFieldAlignment, metadataType.Context.Target.GetObjectAlignment(metadataType.InstanceFieldAlignment));
}
layoutAbiStable = metadataType.LayoutAbiStable;
}
else
Expand Down Expand Up @@ -840,25 +855,29 @@ private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt
}

TargetDetails target = type.Context.Target;
LayoutInt parentSize;
if (type.IsValueType || type.BaseType == null)
parentSize = new LayoutInt(0);
else
parentSize = type.BaseType.InstanceByteCountUnaligned;
LayoutInt specifiedInstanceSize = parentSize + new LayoutInt(classLayoutSize);

if (classLayoutSize != 0)
if (!instanceSize.IsIndeterminate && specifiedInstanceSize.AsInt >= instanceSize.AsInt)
{
LayoutInt parentSize;
if (type.IsValueType)
parentSize = new LayoutInt(0);
else
parentSize = type.BaseType.InstanceByteCountUnaligned;

LayoutInt specifiedInstanceSize = parentSize + new LayoutInt(classLayoutSize);

instanceSize = LayoutInt.Max(specifiedInstanceSize, instanceSize);
instanceSize = specifiedInstanceSize;
}
else
else if (type.IsValueType)
{
if (type.IsValueType)
LayoutInt sizeAlignment;
if (type.IsEnum || type.IsPrimitive)
{
sizeAlignment = alignment;
}
else
{
instanceSize = LayoutInt.AlignUp(instanceSize, alignment, target);
sizeAlignment = LayoutInt.Min(alignment, target.GetObjectAlignment(alignment));
}
instanceSize = LayoutInt.AlignUp(instanceSize, sizeAlignment, target);
}

if (type.IsValueType)
Expand Down
11 changes: 9 additions & 2 deletions src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,15 @@ public LayoutInt GetWellKnownTypeSize(DefType type)
/// </summary>
public LayoutInt GetWellKnownTypeAlignment(DefType type)
{
// Size == Alignment for all platforms.
return GetWellKnownTypeSize(type);
// Size == Alignment on 64-bit platforms, arm32 and Windows x86; on Unix x86, Alignment of 8-byte primitives is 4.
LayoutInt typeSize = GetWellKnownTypeSize(type);
if (Architecture == TargetArchitecture.X86 && OperatingSystem != TargetOS.Windows)
{
// Per /~https://github.com/dotnet/runtime/blob/b08a97afb8270511c39fe26d37038877bb63a09b/src/coreclr/vm/classlayoutinfo.cpp#L254
// 8-byte types have alignment 4 on UNIX x86.
typeSize = LayoutInt.Min(typeSize, LayoutPointerSize);
}
return typeSize;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -802,15 +802,46 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada
{
return ComputeExplicitFieldLayout(type, numInstanceFields);
}
else
if (type.IsEnum || MarshalUtils.IsBlittableType(type) || IsManagedSequentialType(type))
else if (LayoutContainsNoGCPointers(type))
{
return ComputeSequentialFieldLayout(type, numInstanceFields);
}
else
return ComputeAutoFieldLayout(type, numInstanceFields);
}

private bool LayoutContainsNoGCPointers(TypeDesc type)
{
if (type.IsPrimitive || type.IsEnum || type.IsPointer || type.IsFunctionPointer)
{
return true;
}
MetadataType mdType = type as MetadataType;
if (mdType == null)
{
return false;
}
if (!mdType.IsValueType && mdType.HasBaseType && !LayoutContainsNoGCPointers(mdType.BaseType))
{
return false;
}
if (!mdType.IsExplicitLayout && !mdType.IsSequentialLayout)
{
return false;
}
if (type.Category == TypeFlags.ValueType ||
type.Category == TypeFlags.Class ||
type.Category == TypeFlags.Nullable)
{
return ComputeAutoFieldLayout(type, numInstanceFields);
foreach (FieldDesc field in type.GetFields())
{
if (!field.IsStatic && (field.FieldType.Category == TypeFlags.Class || !LayoutContainsNoGCPointers(field.FieldType)))
{
return false;
}
}
return true;
}
return false;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2269,13 +2269,7 @@ private bool NeedsTypeLayoutCheck(TypeDesc type)

private bool HasLayoutMetadata(TypeDesc type)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one place where this method is used looks like dead/unrechable code.

This method can only return true when type.IsValueType is true, but this case is handled in EncodeFieldBaseOffset earlier via the else if (pMT.IsValueType) check. It means that this method won't ever return true.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanup, thanks Jan for pointing that out, deleted in 9th commit.

{
if (type.IsValueType && (MarshalUtils.IsBlittableType(type) || ReadyToRunMetadataFieldLayoutAlgorithm.IsManagedSequentialType(type)))
{
// Sequential layout
return true;
}

return false;
return type is MetadataType metadataType && (metadataType.IsSequentialLayout || metadataType.IsExplicitLayout);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also delete/replace IsBlittableType from ComputeInstanceFieldLayout so that the layout does not depend on the algorithm to compute blittability?

}

/// <summary>
Expand Down
Loading