Skip to content
Open
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
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