Skip to content

Fix explicit offset of ByRefLike fields. #111584

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

Merged
merged 16 commits into from
Jan 31, 2025
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 @@ -61,6 +61,12 @@ public override bool ComputeContainsGCPointers(DefType type)
return false;
}

public override bool ComputeContainsByRefs(DefType type)
{
Debug.Assert(!_fallbackAlgorithm.ComputeContainsByRefs(type));
return false;
}

public override bool ComputeIsUnsafeValueType(DefType type)
{
Debug.Assert(!_fallbackAlgorithm.ComputeIsUnsafeValueType(type));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ public override bool ComputeContainsGCPointers(DefType type)
return false;
}

public override bool ComputeContainsByRefs(DefType type)
{
Debug.Assert(!_fallbackAlgorithm.ComputeContainsByRefs(type));
return false;
}

public override bool ComputeIsUnsafeValueType(DefType type)
{
Debug.Assert(!_fallbackAlgorithm.ComputeIsUnsafeValueType(type));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ protected override LoweredType GetIntervalDataForType(int offset, TypeDesc field
return LoweredType.Opaque;
}

protected override bool NeedsRecursiveLayout(int offset, TypeDesc fieldType) => fieldType.IsValueType && !fieldType.IsPrimitiveNumeric;
protected override bool NeedsRecursiveLayout(TypeDesc fieldType) => fieldType.IsValueType && !fieldType.IsPrimitiveNumeric;

private List<FieldLayoutInterval> CreateConsolidatedIntervals()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ private static class FieldLayoutFlags
/// True if the type transitively has a Vector<T> in it or is Vector<T>
/// </summary>
public const int IsVectorTOrHasVectorTFields = 0x1000;

/// <summary>
/// True if ContainsByRefs has been computed
/// </summary>
public const int ComputedContainsByRefs = 0x2000;

/// <summary>
/// True if the type contains byrefs
/// </summary>
public const int ContainsByRefs = 0x4000;
}

private sealed class StaticBlockInfo
Expand Down Expand Up @@ -113,6 +123,21 @@ public bool ContainsGCPointers
}
}

/// <summary>
/// Does a type transitively have any fields which are byrefs
/// </summary>
public bool ContainsByRefs
{
get
{
if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedContainsByRefs))
{
ComputeTypeContainsByRefs();
}
return _fieldLayoutFlags.HasFlags(FieldLayoutFlags.ContainsByRefs);
}
}

/// <summary>
/// Does a type transitively have any fields which are marked with System.Runtime.CompilerServices.UnsafeValueTypeAttribute
/// </summary>
Expand Down Expand Up @@ -545,6 +570,20 @@ public void ComputeTypeContainsGCPointers()
_fieldLayoutFlags.AddFlags(flagsToAdd);
}

public void ComputeTypeContainsByRefs()
{
if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedContainsByRefs))
return;

int flagsToAdd = FieldLayoutFlags.ComputedContainsByRefs;
if (this.Context.GetLayoutAlgorithmForType(this).ComputeContainsByRefs(this))
{
flagsToAdd |= FieldLayoutFlags.ContainsByRefs;
}

_fieldLayoutFlags.AddFlags(flagsToAdd);
}

public void ComputeIsUnsafeValueType()
{
if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedIsUnsafeValueType))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ protected override FieldLayoutTag GetIntervalDataForType(int offset, TypeDesc fi
else if (fieldType.IsValueType)
{
MetadataType mdType = (MetadataType)fieldType;
if (!mdType.ContainsGCPointers && !mdType.IsByRefLike)
if (!mdType.ContainsGCPointers && !mdType.ContainsByRefs)
{
// Plain value type, mark the entire range as NonORef
return FieldLayoutTag.NonORef;
}
Debug.Fail("We should recurse on value types with GC pointers or ByRefLike types");
Debug.Fail("We should recurse on value types with GC pointers or byrefs");
return FieldLayoutTag.Empty;
}
else
Expand All @@ -74,20 +74,16 @@ protected override FieldLayoutTag GetIntervalDataForType(int offset, TypeDesc fi
}
}

protected override bool NeedsRecursiveLayout(int offset, TypeDesc fieldType)
protected override bool NeedsRecursiveLayout(TypeDesc fieldType)
{
if (!fieldType.IsValueType || !((MetadataType)fieldType).ContainsGCPointers && !fieldType.IsByRefLike)
if (!fieldType.IsValueType)
{
return false;
}

if (offset % PointerSize != 0)
{
// Misaligned struct with GC pointers or ByRef
ThrowFieldLayoutError(offset);
}

return true;
// Valuetypes with GC references or byrefs need to be checked for overlaps and alignment
MetadataType mdType = (MetadataType)fieldType;
return mdType.ContainsGCPointers || mdType.ContainsByRefs;
}

private void ThrowFieldLayoutError(int offset)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public abstract class FieldLayoutAlgorithm
/// </summary>
public abstract bool ComputeContainsGCPointers(DefType type);

/// <summary>
/// Compute whether the fields of the specified type contains a byref.
/// </summary>
public abstract bool ComputeContainsByRefs(DefType type);

/// <summary>
/// Compute whether the specified type is a value type that transitively has UnsafeValueTypeAttribute
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public FieldLayoutIntervalCalculator(int pointerSize)
PointerSize = pointerSize;
}

protected abstract bool NeedsRecursiveLayout(int offset, TypeDesc fieldType);
protected abstract bool NeedsRecursiveLayout(TypeDesc fieldType);

protected abstract TIntervalTag GetIntervalDataForType(int offset, TypeDesc fieldType);

Expand Down Expand Up @@ -84,7 +84,7 @@ private int GetFieldSize(TypeDesc fieldType)

public void AddToFieldLayout(int offset, TypeDesc fieldType, bool addTrailingEmptyInterval)
{
if (NeedsRecursiveLayout(offset, fieldType))
if (NeedsRecursiveLayout(fieldType))
{
if (fieldType is MetadataType { IsInlineArray: true } mdType)
{
Expand Down Expand Up @@ -126,7 +126,7 @@ public void AddToFieldLayout(int offset, TypeDesc fieldType, bool addTrailingEmp

private void AddToFieldLayout(List<FieldLayoutInterval> fieldLayout, int offset, TypeDesc fieldType)
{
if (NeedsRecursiveLayout(offset, fieldType))
if (NeedsRecursiveLayout(fieldType))
{
if (fieldType is MetadataType { IsInlineArray: true } mdType)
{
Expand Down
Loading
Loading