Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions src/coreclr/dlls/mscorrc/mscorrc.rc
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ BEGIN
IDS_EE_BADMARSHAL_CUSTOMMARSHALER "Custom marshalers are only allowed on classes, strings, arrays, and boxed value types."
IDS_EE_BADMARSHAL_GENERICS_RESTRICTION "Non-blittable generic types cannot be marshaled."
IDS_EE_BADMARSHAL_INT128_RESTRICTION "System.Int128 and System.UInt128 cannot be passed by value to unmanaged."
IDS_EE_BADMARSHAL_DECIMAL_RESTRICTION "System.Numerics.Decimal32, System.Numerics.Decimal64, and System.Numerics.Decimal128 cannot be passed by value to unmanaged."
IDS_EE_BADMARSHAL_AUTOLAYOUT "Structures marked with [StructLayout(LayoutKind.Auto)] cannot be marshaled."
IDS_EE_BADMARSHAL_STRING_OUT "Cannot marshal a string by-value with the [Out] attribute."
IDS_EE_BADMARSHAL_MARSHAL_DISABLED "Cannot marshal managed types when the runtime marshalling system is disabled."
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/dlls/mscorrc/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@
#define IDS_EE_BADMARSHAL_ABSTRACTOUTCRITICALHANDLE 0x1a63
#define IDS_EE_BADMARSHAL_CRITICALHANDLE 0x1a65
#define IDS_EE_BADMARSHAL_INT128_RESTRICTION 0x1a66
#define IDS_EE_BADMARSHAL_DECIMAL_RESTRICTION 0x1a67

#define IDS_EE_BADMARSHAL_ABSTRACTRETCRITICALHANDLE 0x1a6a

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler
{
/// <summary>
/// Represents an algorithm that computes field layout for the IEEE 754 decimal floating-point
/// types (Decimal32/Decimal64/Decimal128). Decimal128 shares the 16-byte packing requirement of
/// Int128/UInt128; Decimal32/Decimal64 keep the natural alignment of their underlying scalar.
/// </summary>
public class DecimalFieldLayoutAlgorithm : FieldLayoutAlgorithm
{
private readonly FieldLayoutAlgorithm _fallbackAlgorithm;

public DecimalFieldLayoutAlgorithm(FieldLayoutAlgorithm fallbackAlgorithm)
{
_fallbackAlgorithm = fallbackAlgorithm;
}

public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defType, InstanceLayoutKind layoutKind)
{
Debug.Assert(IsDecimalFloatingPointType(defType));

ComputedInstanceFieldLayout layoutFromMetadata = _fallbackAlgorithm.ComputeInstanceLayout(defType, layoutKind);

// Only Decimal128 corresponds to a 16-byte ABI primitive (_Decimal128) requiring the packing
// applied to Int128/UInt128; Decimal32/Decimal64 keep the natural alignment of uint/ulong.
// ARM32 has no such primitive in its PCS, so it uses the metadata layout as Int128 does.
// x86 and WASM are still 16-byte aligned, matching the Int128/UInt128 treatment.
if (defType.Name != "Decimal128"u8
|| defType.Context.Target.Architecture == TargetArchitecture.ARM)
{
layoutFromMetadata.LayoutAbiStable = true;
layoutFromMetadata.IsDecimalFloatingPointOrHasDecimalFloatingPointFields = true;
return layoutFromMetadata;
}

return new ComputedInstanceFieldLayout
{
ByteCountUnaligned = layoutFromMetadata.ByteCountUnaligned,
ByteCountAlignment = layoutFromMetadata.ByteCountAlignment,
FieldAlignment = new LayoutInt(16),
FieldSize = layoutFromMetadata.FieldSize,
Offsets = layoutFromMetadata.Offsets,
LayoutAbiStable = true,
IsDecimalFloatingPointOrHasDecimalFloatingPointFields = true
};
}

public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defType, StaticLayoutKind layoutKind)
{
return _fallbackAlgorithm.ComputeStaticFieldLayout(defType, layoutKind);
}

public override bool ComputeContainsGCPointers(DefType type)
{
Debug.Assert(!_fallbackAlgorithm.ComputeContainsGCPointers(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));
return false;
}

public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type)
{
Debug.Assert(_fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type) == ValueTypeShapeCharacteristics.None);
return ValueTypeShapeCharacteristics.None;
}

public static bool IsDecimalFloatingPointType(DefType type)
{
return type.IsIntrinsic
&& type.Namespace == "System.Numerics"u8
&& (type.Name == "Decimal32"u8 || type.Name == "Decimal64"u8 || type.Name == "Decimal128"u8);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ private static class FieldLayoutFlags
/// True if the type contains byrefs
/// </summary>
public const int ContainsByRefs = 0x4000;

/// <summary>
/// True if the type transitively has a decimal floating-point type
/// (Decimal32/Decimal64/Decimal128) in it or is one.
/// </summary>
public const int IsDecimalFloatingPointOrHasDecimalFloatingPointFields = 0x8000;
}

private sealed class StaticBlockInfo
Expand Down Expand Up @@ -198,6 +204,22 @@ public virtual bool IsVectorTOrHasVectorTFields
}
}

/// <summary>
/// Is a type a decimal floating-point type (Decimal32/Decimal64/Decimal128) or transitively
/// have any fields of such a type.
/// </summary>
public virtual bool IsDecimalFloatingPointOrHasDecimalFloatingPointFields
{
get
{
if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout))
{
ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields);
}
return _fieldLayoutFlags.HasFlags(FieldLayoutFlags.IsDecimalFloatingPointOrHasDecimalFloatingPointFields);
}
}

/// <summary>
/// The number of bytes required to hold a field of this type
/// </summary>
Expand Down Expand Up @@ -500,6 +522,10 @@ public void ComputeInstanceLayout(InstanceLayoutKind layoutKind)
{
_fieldLayoutFlags.AddFlags(FieldLayoutFlags.IsVectorTOrHasVectorTFields);
}
if (computedLayout.IsDecimalFloatingPointOrHasDecimalFloatingPointFields)
{
_fieldLayoutFlags.AddFlags(FieldLayoutFlags.IsDecimalFloatingPointOrHasDecimalFloatingPointFields);
}

if (computedLayout.Offsets != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ public struct ComputedInstanceFieldLayout
public bool IsAutoLayoutOrHasAutoLayoutFields;
public bool IsInt128OrHasInt128Fields;
public bool IsVectorTOrHasVectorTFields;
public bool IsDecimalFloatingPointOrHasDecimalFloatingPointFields;

/// <summary>
/// If Offsets is non-null, then all field based layout is complete.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ out instanceByteSizeAndAlignment
IsAutoLayoutOrHasAutoLayoutFields = false,
IsInt128OrHasInt128Fields = false,
IsVectorTOrHasVectorTFields = false,
IsDecimalFloatingPointOrHasDecimalFloatingPointFields = false,
};

if (numInstanceFields > 0)
Expand Down Expand Up @@ -325,11 +326,13 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty
bool hasAutoLayoutField = false;
bool hasInt128Field = false;
bool hasVectorTField = false;
bool hasDecimalField = false;

if (type.BaseType is not null)
{
hasInt128Field = type.BaseType.IsInt128OrHasInt128Fields;
hasVectorTField = type.BaseType.IsVectorTOrHasVectorTFields;
hasDecimalField = type.BaseType.IsDecimalFloatingPointOrHasDecimalFloatingPointFields;
}

foreach (FieldDesc field in type.GetFields())
Expand All @@ -347,6 +350,8 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty
hasInt128Field = true;
if (fieldData.HasVectorTField)
hasVectorTField = true;
if (fieldData.HasDecimalField)
hasDecimalField = true;

largestAlignmentRequired = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequired);

Expand Down Expand Up @@ -401,6 +406,7 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty
IsAutoLayoutOrHasAutoLayoutFields = hasAutoLayoutField,
IsInt128OrHasInt128Fields = hasInt128Field,
IsVectorTOrHasVectorTFields = hasVectorTField,
IsDecimalFloatingPointOrHasDecimalFloatingPointFields = hasDecimalField,
};
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
computedLayout.FieldSize = instanceSizeAndAlignment.Size;
Expand Down Expand Up @@ -436,11 +442,13 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType
bool hasAutoLayoutField = false;
bool hasInt128Field = false;
bool hasVectorTField = false;
bool hasDecimalField = false;

if (type.BaseType is not null)
{
hasInt128Field = type.BaseType.IsInt128OrHasInt128Fields;
hasVectorTField = type.BaseType.IsVectorTOrHasVectorTFields;
hasDecimalField = type.BaseType.IsDecimalFloatingPointOrHasDecimalFloatingPointFields;
}

foreach (var field in type.GetFields())
Expand All @@ -457,6 +465,8 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType
hasInt128Field = true;
if (fieldData.HasVectorTField)
hasVectorTField = true;
if (fieldData.HasDecimalField)
hasDecimalField = true;

largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement);

Expand Down Expand Up @@ -485,6 +495,7 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType
IsAutoLayoutOrHasAutoLayoutFields = hasAutoLayoutField,
IsInt128OrHasInt128Fields = hasInt128Field,
IsVectorTOrHasVectorTFields = hasVectorTField,
IsDecimalFloatingPointOrHasDecimalFloatingPointFields = hasDecimalField,
};
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
computedLayout.FieldSize = instanceSizeAndAlignment.Size;
Expand Down Expand Up @@ -514,6 +525,7 @@ protected ComputedInstanceFieldLayout ComputeCStructFieldLayout(MetadataType typ
bool hasAutoLayoutField = false;
bool hasInt128Field = false;
bool hasVectorTField = false;
bool hasDecimalField = false;

foreach (var field in type.GetFields())
{
Expand All @@ -529,6 +541,8 @@ protected ComputedInstanceFieldLayout ComputeCStructFieldLayout(MetadataType typ
hasInt128Field = true;
if (fieldData.HasVectorTField)
hasVectorTField = true;
if (fieldData.HasDecimalField)
hasDecimalField = true;

largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement);

Expand Down Expand Up @@ -570,6 +584,7 @@ protected ComputedInstanceFieldLayout ComputeCStructFieldLayout(MetadataType typ
IsAutoLayoutOrHasAutoLayoutFields = false,
IsInt128OrHasInt128Fields = hasInt128Field,
IsVectorTOrHasVectorTFields = hasVectorTField,
IsDecimalFloatingPointOrHasDecimalFloatingPointFields = hasDecimalField,
FieldAlignment = instanceSizeAndAlignment.Alignment,
FieldSize = instanceSizeAndAlignment.Size,
ByteCountUnaligned = instanceByteSizeAndAlignment.Size,
Expand Down Expand Up @@ -599,6 +614,7 @@ protected ComputedInstanceFieldLayout ComputeCUnionFieldLayout(MetadataType type
bool hasAutoLayoutField = false;
bool hasInt128Field = false;
bool hasVectorTField = false;
bool hasDecimalField = false;

foreach (var field in type.GetFields())
{
Expand All @@ -614,6 +630,8 @@ protected ComputedInstanceFieldLayout ComputeCUnionFieldLayout(MetadataType type
hasInt128Field = true;
if (fieldData.HasVectorTField)
hasVectorTField = true;
if (fieldData.HasDecimalField)
hasDecimalField = true;

largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement);
largestFieldSize = LayoutInt.Max(fieldSizeAndAlignment.Size, largestFieldSize);
Expand Down Expand Up @@ -655,6 +673,7 @@ protected ComputedInstanceFieldLayout ComputeCUnionFieldLayout(MetadataType type
IsAutoLayoutOrHasAutoLayoutFields = false,
IsInt128OrHasInt128Fields = hasInt128Field,
IsVectorTOrHasVectorTFields = hasVectorTField,
IsDecimalFloatingPointOrHasDecimalFloatingPointFields = hasDecimalField,
FieldAlignment = instanceSizeAndAlignment.Alignment,
FieldSize = instanceSizeAndAlignment.Size,
ByteCountUnaligned = instanceByteSizeAndAlignment.Size,
Expand Down Expand Up @@ -736,6 +755,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
int[] instanceNonGCPointerFieldsCount = new int[maxLog2Size + 1];
bool hasInt128Field = false;
bool hasVectorTField = false;
bool hasDecimalField = false;

foreach (var field in type.GetFields())
{
Expand All @@ -752,6 +772,8 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
hasInt128Field = true;
if (((DefType)fieldType).IsVectorTOrHasVectorTFields)
hasVectorTField = true;
if (((DefType)fieldType).IsDecimalFloatingPointOrHasDecimalFloatingPointFields)
hasDecimalField = true;
}
else if (fieldType.IsGCPointer)
{
Expand Down Expand Up @@ -1026,6 +1048,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
IsAutoLayoutOrHasAutoLayoutFields = true,
IsInt128OrHasInt128Fields = hasInt128Field,
IsVectorTOrHasVectorTFields = hasVectorTField,
IsDecimalFloatingPointOrHasDecimalFloatingPointFields = hasDecimalField,
};
computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment;
computedLayout.FieldSize = instanceSizeAndAlignment.Size;
Expand Down Expand Up @@ -1105,6 +1128,7 @@ private struct ComputedFieldData
public bool HasAutoLayout;
public bool HasInt128Field;
public bool HasVectorTField;
public bool HasDecimalField;
}

private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, bool hasLayout, int packingSize, out ComputedFieldData fieldData)
Expand All @@ -1116,7 +1140,8 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType,
LayoutAbiStable = true,
HasAutoLayout = true,
HasInt128Field = false,
HasVectorTField = false
HasVectorTField = false,
HasDecimalField = false
};

if (fieldType.IsDefType)
Expand All @@ -1130,6 +1155,7 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType,
fieldData.HasAutoLayout = defType.IsAutoLayoutOrHasAutoLayoutFields;
fieldData.HasInt128Field = defType.IsInt128OrHasInt128Fields;
fieldData.HasVectorTField = defType.IsVectorTOrHasVectorTFields;
fieldData.HasDecimalField = defType.IsDecimalFloatingPointOrHasDecimalFloatingPointFields;
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,12 @@ internal static MarshallerKind GetMarshallerKind(
return MarshallerKind.Invalid;
}

if (!isField && ((DefType)type).IsDecimalFloatingPointOrHasDecimalFloatingPointFields && !isByRef)
{
// Decimal32/64/128 types or structs that contain them cannot be passed by value
return MarshallerKind.Invalid;
}

if (!isField && ((DefType)type).IsVectorTOrHasVectorTFields)
{
// Vector<T> types or structs that contain them cannot be passed by value
Expand Down Expand Up @@ -922,6 +928,7 @@ internal static MarshallerKind GetDisabledMarshallerKind(
if (!defType.ContainsGCPointers
&& !defType.IsAutoLayoutOrHasAutoLayoutFields
&& !defType.IsInt128OrHasInt128Fields
&& !defType.IsDecimalFloatingPointOrHasDecimalFloatingPointFields
&& IsValidForGenericMarshalling(defType, isFieldScenario, builtInMarshallingEnabled: false))
{
return MarshallerKind.BlittableValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public SharedGenericsConfiguration GenericsConfig
private readonly VectorOfTFieldLayoutAlgorithm _vectorOfTFieldLayoutAlgorithm;
private readonly VectorFieldLayoutAlgorithm _vectorFieldLayoutAlgorithm;
private readonly Int128FieldLayoutAlgorithm _int128FieldLayoutAlgorithm;
private readonly DecimalFieldLayoutAlgorithm _decimalFieldLayoutAlgorithm;
private readonly TypeWithRepeatedFieldsFieldLayoutAlgorithm _typeWithRepeatedFieldsFieldLayoutAlgorithm;

private TypeDesc[] _arrayOfTInterfaces;
Expand All @@ -58,6 +59,7 @@ public CompilerTypeSystemContext(TargetDetails details, SharedGenericsMode gener
_vectorOfTFieldLayoutAlgorithm = new VectorOfTFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
_vectorFieldLayoutAlgorithm = new VectorFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
_int128FieldLayoutAlgorithm = new Int128FieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
_decimalFieldLayoutAlgorithm = new DecimalFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);
_typeWithRepeatedFieldsFieldLayoutAlgorithm = new TypeWithRepeatedFieldsFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm);

_delegateInfoHashtable = new DelegateInfoHashtable(delegateFeatures);
Expand Down Expand Up @@ -116,6 +118,8 @@ public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type)
return _vectorFieldLayoutAlgorithm;
else if (Int128FieldLayoutAlgorithm.IsIntegerType(type))
return _int128FieldLayoutAlgorithm;
else if (DecimalFieldLayoutAlgorithm.IsDecimalFloatingPointType(type))
return _decimalFieldLayoutAlgorithm;
else if (type is TypeWithRepeatedFields)
return _typeWithRepeatedFieldsFieldLayoutAlgorithm;
else
Expand Down
Loading
Loading