This commit is contained in:
Jeremy Koritzinsky 2025-07-31 02:07:51 +12:00 committed by GitHub
commit b322344c93
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
65 changed files with 6756 additions and 5788 deletions

View File

@ -24,6 +24,7 @@ This is a list of additions and edits to be made in ECMA-335 specifications. It
- [Creating arrays using newobj](#creating-arrays-using-newobj)
- [API documentation](#api-documentation)
- [Debug Interchange Format](#debug-interchange-format)
- [Extended layout](#extended-layout)
## Signatures
@ -1147,3 +1148,45 @@ The incorrect description of `System.Array.Initialize` API in section "II.13.2 I
## Debug Interchange Format
The Debug Interchange Format described in partition V is superseded by the [Portable PDB Format](PortablePdb-Metadata.md).
## Extended Layout
In section I.9.5, the following layout rule is added:
- **extendedlayout**: A class marked `extendedlayout` guides the loader to use a set of rules indicated by the first parameter to a custom attribute of type `System.Runtime.InteropServices.ExtendedLayoutAttribute` on the type. Each of these layouts may have restrictions on valid layouts.
In section II.10.1, `extended` is added as a possible value for `ClassAttr`.
In section II.10.1.2, `extended` is added as a type layout attribute, and the following entry is added in the list of layout attributes:
- **extended**: The CLI shal lay out the files based on the rules indicated by the first parameter to a custom attribute of type `System.Runtime.InteropServices.ExtendedLayoutAttribute` on the type.
In section II.10.7, the following clause is appended:
The **.pack** and **.size** directives are not valid on a type marked with `extended`.
In section II.22.8, the following diffs are applied:
```diff
- The information held in the ClassLayout table depends upon the Flags value for {AutoLayout, SequentialLayout, ExplicitLayout} in the owner class or value type.
- A type has layout if it is marked SequentialLayout or ExplicitLayout. If any type within an inheritance chain has layout, then so shall all its base classes, up to the one that descends immediately from System.ValueType (if it exists in the types hierarchy); otherwise, from System.Object.
+ The information held in the ClassLayout table depends upon the Flags value for {AutoLayout, SequentialLayout, ExplicitLayout, ExtendedLayout} in the owner class or value type.
+ A type has layout if it is marked SequentialLayout or ExplicitLayout or ExtendedLayout.
+ A type with ExtendedLayout must immediately inherit from System.ValueType.
+ If any type within an inheritance chain has layout, then so shall all its base classes, up to the one that descends immediately from System.ValueType (if it exists in the types hierarchy); otherwise, from System.Object.
```
```diff
- 3. The Class or ValueType indexed by Parent shall be SequentialLayout or ExplicitLayout (§II.23.1.15). (That is, AutoLayout types shall not own any rows in the ClassLayout table.) [ERROR]
+ 3. The Class or ValueType indexed by Parent shall be SequentialLayout or ExplicitLayout (§II.23.1.15). (That is, AutoLayout and ExtendedLayout types shall not own any rows in the ClassLayout table.) [ERROR]
```
In section II.22.37, the following clause is removed:
b. can set 0 or 1 of `SequentialLayout` and `ExplicitLayout` (if none set, then defaults to `AutoLayout`) [ERROR]
In section II.23.1.15, the following row is added to the table:
|-----|------|------|
| `ExtendedLayout` | 0x00000018 | Layout is supplied by a `System.Runtime.InteropServices.ExtendedLayoutAttribute` custom attribute |

View File

@ -6,6 +6,7 @@
<PackageDescription>IL verification library.</PackageDescription>
<PackageReleaseNotes>
9.0.0 - In the ILVerify.IResolver interface, the type of the first parameter of each method is now System.Reflection.Metadata.AssemblyNameInfo rather than System.Reflection.AssemblyName.
10.0.0 - The ILVerification package now targets .NET 10.0 and later.
</PackageReleaseNotes>
</PropertyGroup>
@ -15,13 +16,8 @@
<ItemGroup>
<PackageFile Include="$(ArtifactsDir)bin\ILVerification\$(TargetArchitecture)\$(Configuration)\ILVerification.dll">
<TargetPath>lib\netstandard2.0\ILVerification.dll</TargetPath>
<TargetPath>lib\$(NetCoreAppToolCurrent)\ILVerification.dll</TargetPath>
</PackageFile>
<Dependency Include="System.Reflection.Metadata">
<Version>$(SystemReflectionMetadataVersion)</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<Exclude>Build,Analyzers</Exclude>
</Dependency>
</ItemGroup>
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.targets))" />

View File

@ -519,12 +519,6 @@ namespace System.Reflection.Emit
}
}
// Verify that the layout mask is valid.
if (((attr & TypeAttributes.LayoutMask) != TypeAttributes.AutoLayout) && ((attr & TypeAttributes.LayoutMask) != TypeAttributes.SequentialLayout) && ((attr & TypeAttributes.LayoutMask) != TypeAttributes.ExplicitLayout))
{
throw new ArgumentException(SR.Argument_BadTypeAttrInvalidLayout);
}
// Check if the user attempted to set any reserved bits.
if ((attr & TypeAttributes.ReservedMask) != 0)
{

View File

@ -2272,6 +2272,7 @@ namespace System.Reflection
case TypeAttributes.ExplicitLayout: layoutKind = LayoutKind.Explicit; break;
case TypeAttributes.AutoLayout: layoutKind = LayoutKind.Auto; break;
case TypeAttributes.SequentialLayout: layoutKind = LayoutKind.Sequential; break;
case TypeAttributes.ExtendedLayout: layoutKind = LayoutKind.Extended; break;
default: Debug.Fail("Unreachable code"); break;
}

View File

@ -76,7 +76,7 @@
%token VALUE_ VALUETYPE_ NATIVE_ INSTANCE_ SPECIALNAME_ FORWARDER_
%token STATIC_ PUBLIC_ PRIVATE_ FAMILY_ FINAL_ SYNCHRONIZED_ INTERFACE_ SEALED_ NESTED_
%token ABSTRACT_ AUTO_ SEQUENTIAL_ EXPLICIT_ ANSI_ UNICODE_ AUTOCHAR_ IMPORT_ ENUM_
%token ABSTRACT_ AUTO_ SEQUENTIAL_ EXPLICIT_ EXTENDED_ ANSI_ UNICODE_ AUTOCHAR_ IMPORT_ ENUM_
%token VIRTUAL_ NOINLINING_ AGGRESSIVEINLINING_ NOOPTIMIZATION_ AGGRESSIVEOPTIMIZATION_ UNMANAGEDEXP_ BEFOREFIELDINIT_ ASYNC_
%token STRICT_ RETARGETABLE_ WINDOWSRUNTIME_ NOPLATFORM_
%token METHOD_ FIELD_ PINNED_ MODREQ_ MODOPT_ SERIALIZABLE_ PROPERTY_ TYPE_
@ -260,6 +260,7 @@ id : ID { $$ = $1; }
| NOOPTIMIZATION_ { $$ = newString("nooptimization"); }
| AGGRESSIVEOPTIMIZATION_ { $$ = newString("aggressiveoptimization"); }
| ASYNC_ { $$ = newString("async"); }
| EXTENDED_ { $$ = newString("extended"); }
| SQSTRING { $$ = $1; }
;
@ -444,6 +445,7 @@ classAttr : /* EMPTY */ { $$ = (CorRegTypeAt
| classAttr AUTO_ { $$ = (CorRegTypeAttr) (($1 & ~tdLayoutMask) | tdAutoLayout); }
| classAttr SEQUENTIAL_ { $$ = (CorRegTypeAttr) (($1 & ~tdLayoutMask) | tdSequentialLayout); }
| classAttr EXPLICIT_ { $$ = (CorRegTypeAttr) (($1 & ~tdLayoutMask) | tdExplicitLayout); }
| classAttr EXTENDED_ { $$ = (CorRegTypeAttr) (($1 & ~tdLayoutMask) | tdExtendedLayout); }
| classAttr ANSI_ { $$ = (CorRegTypeAttr) (($1 & ~tdStringFormatMask) | tdAnsiClass); }
| classAttr UNICODE_ { $$ = (CorRegTypeAttr) (($1 & ~tdStringFormatMask) | tdUnicodeClass); }
| classAttr AUTOCHAR_ { $$ = (CorRegTypeAttr) (($1 & ~tdStringFormatMask) | tdAutoClass); }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1133,6 +1133,7 @@ BOOL PrintClassList()
if (IsTdAbstract(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(abstract) ");
if (IsTdAutoLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(auto) ");
if (IsTdSequentialLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(sequential) ");
if (IsTdExtendedLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(extended) ");
if (IsTdExplicitLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(explicit) ");
if (IsTdAnsiClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(ansi) ");
if (IsTdUnicodeClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"(unicode) ");
@ -4684,6 +4685,7 @@ BOOL DumpClass(mdTypeDef cl, DWORD dwEntryPointToken, void* GUICookie, ULONG Wha
if (IsTdAutoLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"auto ");
if (IsTdSequentialLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"sequential ");
if (IsTdExplicitLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"explicit ");
if (IsTdExtendedLayout(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"extended ");
if (IsTdAnsiClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"ansi ");
if (IsTdUnicodeClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"unicode ");
if (IsTdAutoClass(dwClassAttrs)) szptr+=sprintf_s(szptr,SZSTRING_REMAINING_SIZE(szptr),"autochar ");

View File

@ -288,6 +288,7 @@ typedef enum CorTypeAttr
tdAutoLayout = 0x00000000, // Class fields are auto-laid out
tdSequentialLayout = 0x00000008, // Class fields are laid out sequentially
tdExplicitLayout = 0x00000010, // Layout is supplied explicitly
tdExtendedLayout = 0x00000018, // Layout is supplied via the System.Runtime.InteropServices.ExtendedLayoutAttribute
// end layout mask
// Use this mask to retrieve class semantics information.
@ -325,6 +326,10 @@ typedef enum CorTypeAttr
tdHasSecurity = 0x00040000, // Class has security associate with it.
} CorTypeAttr;
enum class CorExtendedLayoutKind
{
CStruct = 0, // C-style struct
};
// Macros for accessing the members of the CorTypeAttr.
#define IsTdNotPublic(x) (((x) & tdVisibilityMask) == tdNotPublic)
@ -340,6 +345,7 @@ typedef enum CorTypeAttr
#define IsTdAutoLayout(x) (((x) & tdLayoutMask) == tdAutoLayout)
#define IsTdSequentialLayout(x) (((x) & tdLayoutMask) == tdSequentialLayout)
#define IsTdExplicitLayout(x) (((x) & tdLayoutMask) == tdExplicitLayout)
#define IsTdExtendedLayout(x) (((x) & tdLayoutMask) == tdExtendedLayout)
#define IsTdClass(x) (((x) & tdClassSemanticsMask) == tdClass)
#define IsTdInterface(x) (((x) & tdClassSemanticsMask) == tdInterface)

View File

@ -66,6 +66,7 @@
KYWD( "auto", AUTO_, NO_VALUE )
KYWD( "sequential", SEQUENTIAL_, NO_VALUE )
KYWD( "explicit", EXPLICIT_, NO_VALUE )
KYWD( "extended", EXTENDED_, NO_VALUE )
KYWD( "ansi", ANSI_, NO_VALUE )
KYWD( "unicode", UNICODE_, NO_VALUE )
KYWD( "autochar", AUTOCHAR_, NO_VALUE )

View File

@ -1349,6 +1349,9 @@ HRESULT RegMeta::_HandleKnownCustomAttribute( // S_OK or error.
case 0: // tdSequentialLayout:
dwFlags = (dwFlags & ~tdLayoutMask) | tdSequentialLayout;
break;
case 1: // tdExtendedLayout:
dwFlags = (dwFlags & ~tdLayoutMask) | tdExtendedLayout;
break;
case 2: // tdExplicitLayout:
dwFlags = (dwFlags & ~tdLayoutMask) | tdExplicitLayout;
break;

View File

@ -1816,10 +1816,6 @@ HRESULT RegMeta::_DefineTypeDef( // S_OK or error.
ULONG ulStringLen; // Length of the TypeDef string.
int bSuccess; // Return value for SplitPath().
_ASSERTE(IsTdAutoLayout(dwTypeDefFlags) || IsTdSequentialLayout(dwTypeDefFlags) || IsTdExplicitLayout(dwTypeDefFlags));
_ASSERTE(ptd);
_ASSERTE(TypeFromToken(tkExtends) == mdtTypeRef || TypeFromToken(tkExtends) == mdtTypeDef || TypeFromToken(tkExtends) == mdtTypeSpec
|| IsNilToken(tkExtends));

View File

@ -7,6 +7,7 @@ namespace System.Runtime.InteropServices
public enum LayoutKind
{
Sequential = 0, // 0x00000008,
Extended = 1, // 0x00000018,
Explicit = 2, // 0x00000010,
Auto = 3, // 0x00000000,
}

View File

@ -128,6 +128,7 @@ namespace System.Reflection.Runtime.TypeInfos
case TypeAttributes.ExplicitLayout: layoutKind = LayoutKind.Explicit; break;
case TypeAttributes.AutoLayout: layoutKind = LayoutKind.Auto; break;
case TypeAttributes.SequentialLayout: layoutKind = LayoutKind.Sequential; break;
case TypeAttributes.ExtendedLayout: layoutKind = LayoutKind.Extended; break;
default: layoutKind = LayoutKind.Auto; break;
}

View File

@ -2226,7 +2226,7 @@ namespace Internal.JitInterface
{
int alignment = type.Context.Target.PointerSize;
if (type is MetadataType metadataType && metadataType.HasLayout())
if (type is MetadataType metadataType && !metadataType.IsAutoLayout)
{
if (metadataType.IsSequentialLayout || MarshalUtils.IsBlittableType(metadataType))
{

View File

@ -29,6 +29,10 @@ namespace Internal.TypeSystem
public override bool IsExplicitLayout => false;
public override bool IsExtendedLayout => false;
public override bool IsAutoLayout => true;
public override ModuleDesc Module => _context.SystemModule;
public override bool IsModuleType => false;
@ -57,12 +61,6 @@ namespace Internal.TypeSystem
{
return false;
}
public override int GetInlineArrayLength()
{
Debug.Fail("if this can be an inline array, implement GetInlineArrayLength");
throw new InvalidOperationException();
}
}
internal sealed partial class CanonType

View File

@ -40,6 +40,22 @@ namespace Internal.TypeSystem
}
}
public override bool IsExtendedLayout
{
get
{
return _typeDef.IsExtendedLayout;
}
}
public override bool IsAutoLayout
{
get
{
return _typeDef.IsAutoLayout;
}
}
public override bool IsBeforeFieldInit
{
get
@ -86,11 +102,6 @@ namespace Internal.TypeSystem
return _typeDef.HasCustomAttribute(attributeNamespace, attributeName);
}
public override int GetInlineArrayLength()
{
return _typeDef.GetInlineArrayLength();
}
public override MetadataType GetNestedType(string name)
{
// Return the result from the typical type definition.

View File

@ -63,10 +63,17 @@ namespace Internal.TypeSystem
// hierarchy); otherwise, from System.Object
// If the current type isn't ValueType or System.Object and has a layout and the parent type isn't
// ValueType or System.Object then both need to have layout.
if (!type.IsValueType && type.HasLayout())
//
// ExtendedLayout is not supported on non-value types.
if (!type.IsValueType && !type.IsAutoLayout)
{
if (type.IsExtendedLayout)
{
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
}
MetadataType baseType = type.MetadataBaseType;
if (!baseType.IsObject && !baseType.HasLayout())
if (!baseType.IsObject && baseType.IsAutoLayout)
{
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
}
@ -301,7 +308,7 @@ namespace Internal.TypeSystem
{
}
protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType type, int numInstanceFields)
protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType type, int numInstanceFields, in ClassLayoutMetadata layoutMetadata)
{
// 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.
@ -309,7 +316,6 @@ namespace Internal.TypeSystem
LayoutInt cumulativeInstanceFieldPos = CalculateFieldBaseOffset(type, requiresAlign8: false, requiresAlignedBase: false) - offsetBias;
LayoutInt instanceSize = cumulativeInstanceFieldPos + offsetBias;
ClassLayoutMetadata layoutMetadata = type.GetClassLayout();
int packingSize = ComputePackingSize(type, layoutMetadata);
LayoutInt largestAlignmentRequired = LayoutInt.One;
@ -413,7 +419,7 @@ namespace Internal.TypeSystem
return LayoutInt.AlignUp(cumulativeInstanceFieldPos, alignment, target);
}
protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType type, int numInstanceFields)
protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType type, int numInstanceFields, in ClassLayoutMetadata layoutMetadata)
{
var offsets = new FieldAndOffset[numInstanceFields];
@ -423,8 +429,6 @@ namespace Internal.TypeSystem
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();
LayoutInt largestAlignmentRequirement = LayoutInt.One;
int fieldOrdinal = 0;
int packingSize = ComputePackingSize(type, layoutMetadata);
@ -473,7 +477,7 @@ namespace Internal.TypeSystem
if (type.IsInlineArray)
{
AdjustForInlineArray(type, numInstanceFields, ref instanceByteSizeAndAlignment, ref instanceSizeAndAlignment);
AdjustForInlineArray(type, numInstanceFields, layoutMetadata, ref instanceByteSizeAndAlignment, ref instanceSizeAndAlignment);
}
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout
@ -492,13 +496,99 @@ namespace Internal.TypeSystem
return computedLayout;
}
protected ComputedInstanceFieldLayout ComputeCStructFieldLayout(MetadataType type, int numInstanceFields)
{
if (type.ContainsGCPointers || !type.IsValueType)
{
// CStruct layout algorithm does not support GC pointers.
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
}
var offsets = new FieldAndOffset[numInstanceFields];
LayoutInt cumulativeInstanceFieldPos = LayoutInt.Zero;
LayoutInt largestAlignmentRequirement = LayoutInt.One;
int fieldOrdinal = 0;
int packingSize = type.Context.Target.MaximumAlignment;
bool layoutAbiStable = true;
bool hasAutoLayoutField = false;
bool hasInt128Field = false;
bool hasVectorTField = false;
foreach (var field in type.GetFields())
{
if (field.IsStatic)
continue;
var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType.UnderlyingType, hasLayout: true, packingSize, out ComputedFieldData fieldData);
if (!fieldData.LayoutAbiStable)
layoutAbiStable = false;
if (fieldData.HasAutoLayout)
hasAutoLayoutField = true;
if (fieldData.HasInt128Field)
hasInt128Field = true;
if (fieldData.HasVectorTField)
hasVectorTField = true;
largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement);
cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, type.Context.Target);
offsets[fieldOrdinal] = new FieldAndOffset(field, cumulativeInstanceFieldPos);
cumulativeInstanceFieldPos = LayoutInt.AddThrowing(cumulativeInstanceFieldPos, fieldSizeAndAlignment.Size, type);
fieldOrdinal++;
}
if (hasAutoLayoutField)
{
// CStruct does not support auto layout fields
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
}
if (cumulativeInstanceFieldPos == LayoutInt.Zero)
{
// CStruct cannot have zero size.
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
}
if (type.IsInlineArray)
{
// CStruct types cannot be inline arrays
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadBadFormat, type);
}
SizeAndAlignment instanceByteSizeAndAlignment;
var instanceSizeAndAlignment = ComputeInstanceSize(
type,
cumulativeInstanceFieldPos,
largestAlignmentRequirement,
classLayoutSize: 0, // CStruct does not use the size from metadata.
out instanceByteSizeAndAlignment);
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout
{
IsAutoLayoutOrHasAutoLayoutFields = false,
IsInt128OrHasInt128Fields = hasInt128Field,
IsVectorTOrHasVectorTFields = hasVectorTField,
FieldAlignment = instanceSizeAndAlignment.Alignment,
FieldSize = instanceSizeAndAlignment.Size,
ByteCountUnaligned = instanceByteSizeAndAlignment.Size,
ByteCountAlignment = instanceByteSizeAndAlignment.Alignment,
Offsets = offsets,
LayoutAbiStable = layoutAbiStable
};
return computedLayout;
}
private static void AdjustForInlineArray(
MetadataType type,
int instanceFieldCount,
in ClassLayoutMetadata layoutMetadata,
ref SizeAndAlignment instanceByteSizeAndAlignment,
ref SizeAndAlignment instanceSizeAndAlignment)
{
int repeat = type.GetInlineArrayLength();
int repeat = layoutMetadata.InlineArrayLength;
if (repeat <= 0)
{
@ -541,11 +631,11 @@ namespace Internal.TypeSystem
{
}
protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, int numInstanceFields)
protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, int numInstanceFields, in ClassLayoutMetadata layoutMetadata)
{
TypeSystemContext context = type.Context;
bool hasLayout = type.HasLayout();
bool hasLayout = !type.IsAutoLayout;
// Auto-layout in CoreCLR does not respect packing size.
int packingSize = type.Context.Target.MaximumAlignment;
@ -844,7 +934,7 @@ namespace Internal.TypeSystem
if (type.IsInlineArray)
{
AdjustForInlineArray(type, numInstanceFields, ref instanceByteSizeAndAlignment, ref instanceSizeAndAlignment);
AdjustForInlineArray(type, numInstanceFields, layoutMetadata, ref instanceByteSizeAndAlignment, ref instanceSizeAndAlignment);
}
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout
@ -914,7 +1004,7 @@ namespace Internal.TypeSystem
cumulativeInstanceFieldPos = type.BaseType.InstanceByteCountUnaligned;
if (!cumulativeInstanceFieldPos.IsIndeterminate)
{
if (requiresAlignedBase && type.BaseType.IsZeroSizedReferenceType && ((MetadataType)type.BaseType).HasLayout())
if (requiresAlignedBase && type.BaseType.IsZeroSizedReferenceType && !((MetadataType)type.BaseType).IsAutoLayout)
{
cumulativeInstanceFieldPos += LayoutInt.One;
}
@ -988,7 +1078,7 @@ namespace Internal.TypeSystem
return result;
}
private static int ComputePackingSize(MetadataType type, ClassLayoutMetadata layoutMetadata)
private static int ComputePackingSize(MetadataType type, in ClassLayoutMetadata layoutMetadata)
{
if (layoutMetadata.PackingSize == 0)
return type.Context.Target.MaximumAlignment;

View File

@ -33,6 +33,18 @@ namespace Internal.TypeSystem
/// </summary>
public abstract bool IsSequentialLayout { get; }
/// <summary>
/// If true, the type layout is dictated by extended layout rules provided by the
/// System.Runtime.InteropServices.ExtendedLayoutAttribute.
/// </summary>
public abstract bool IsExtendedLayout { get; }
/// <summary>
/// If true, the type layout is dictated by the auto layout rules provided by the runtime.
/// Corresponds to the definition of autolayout semantic defined in the ECMA-335 specification.
/// </summary>
public abstract bool IsAutoLayout { get; }
/// <summary>
/// If true, the type initializer of this type has a relaxed semantic. Corresponds
/// to the definition of beforefieldinit semantic defined in the ECMA-335 specification.
@ -102,13 +114,21 @@ namespace Internal.TypeSystem
return (GetTypeFlags(TypeFlags.IsInlineArray | TypeFlags.AttributeCacheComputed) & TypeFlags.IsInlineArray) != 0;
}
}
public abstract int GetInlineArrayLength();
}
public struct ClassLayoutMetadata
{
public MetadataLayoutKind Kind;
public int InlineArrayLength;
public int PackingSize;
public int Size;
}
public enum MetadataLayoutKind
{
Auto,
Sequential,
Explicit,
CStruct
}
}

View File

@ -65,10 +65,6 @@ namespace Internal.TypeSystem
return paramType.ParameterType;
}
public static bool HasLayout(this MetadataType mdType)
{
return mdType.IsSequentialLayout || mdType.IsExplicitLayout;
}
public static LayoutInt GetElementSize(this TypeDesc type)
{

View File

@ -85,7 +85,6 @@ namespace Internal.TypeSystem
public override bool HasCustomAttribute(string attributeNamespace, string attributeName) => MetadataType.HasCustomAttribute(attributeNamespace, attributeName);
public override IEnumerable<MetadataType> GetNestedTypes() => (IEnumerable<MetadataType>)EmptyTypes;
public override MetadataType GetNestedType(string name) => null;
public override int GetInlineArrayLength() => MetadataType.GetInlineArrayLength();
public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name) => MetadataType.FindMethodsImplWithMatchingDeclName(name);
public override int GetHashCode() => MetadataType.GetHashCode();
protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() => Array.Empty<MethodImplRecord>();
@ -102,6 +101,10 @@ namespace Internal.TypeSystem
public override bool IsSequentialLayout => MetadataType.IsSequentialLayout;
public override bool IsExtendedLayout => MetadataType.IsExtendedLayout;
public override bool IsAutoLayout => MetadataType.IsAutoLayout;
public override bool IsBeforeFieldInit => MetadataType.IsBeforeFieldInit;
public override ModuleDesc Module => MetadataType.Module;

View File

@ -33,7 +33,7 @@ namespace Internal.TypeSystem
int repeat = 1;
if (type.IsInlineArray)
{
repeat = ((MetadataType)type).GetInlineArrayLength();
repeat = type.GetClassLayout().InlineArrayLength;
}
foreach (FieldDesc field in type.GetFields())

View File

@ -18,6 +18,7 @@ namespace Internal.TypeSystem.Ecma
/// </summary>
public sealed partial class EcmaType : MetadataType, EcmaModule.IEntityHandleObject
{
private const TypeAttributes TypeAttributesExtendedLayout = (TypeAttributes)0x00000018;
private EcmaModule _module;
private TypeDefinitionHandle _handle;
@ -551,26 +552,67 @@ namespace Internal.TypeSystem.Ecma
attributeNamespace, attributeName).IsNil;
}
public override int GetInlineArrayLength()
{
Debug.Assert(this.IsInlineArray);
var attr = MetadataReader.GetCustomAttribute(MetadataReader.GetCustomAttributeHandle(_typeDefinition.GetCustomAttributes(),
"System.Runtime.CompilerServices", "InlineArrayAttribute"));
var value = attr.DecodeValue(new CustomAttributeTypeProvider(_module)).FixedArguments[0].Value;
return value is int intValue ? intValue : 0;
}
public override ClassLayoutMetadata GetClassLayout()
{
TypeLayout layout = _typeDefinition.GetLayout();
int inlineArrayLength = 0;
if (IsInlineArray)
{
var attr = MetadataReader.GetCustomAttribute(MetadataReader.GetCustomAttributeHandle(_typeDefinition.GetCustomAttributes(),
"System.Runtime.CompilerServices", "InlineArrayAttribute"));
var value = attr.DecodeValue(new CustomAttributeTypeProvider(_module)).FixedArguments[0].Value;
inlineArrayLength = value is int intValue ? intValue : 0;
}
MetadataLayoutKind layoutKind = MetadataLayoutKind.Auto;
if ((Attributes & TypeAttributes.LayoutMask) == TypeAttributes.SequentialLayout)
{
layoutKind = MetadataLayoutKind.Sequential;
}
else if ((Attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExplicitLayout)
{
layoutKind = MetadataLayoutKind.Explicit;
}
else if ((Attributes & TypeAttributes.LayoutMask) == TypeAttributesExtendedLayout)
{
var attrHandle = MetadataReader.GetCustomAttributeHandle(_typeDefinition.GetCustomAttributes(),
"System.Runtime.InteropServices", "ExtendedLayoutAttribute");
if (attrHandle.IsNil)
{
ThrowHelper.ThrowTypeLoadException(this);
}
var attr = MetadataReader.GetCustomAttribute(attrHandle);
var attrValue = attr.DecodeValue(new CustomAttributeTypeProvider(_module));
if (attrValue.FixedArguments is not [{ Value: int kind }])
{
ThrowHelper.ThrowTypeLoadException(this);
return default;
}
switch (kind)
{
case 0:
layoutKind = MetadataLayoutKind.CStruct;
break;
default:
ThrowHelper.ThrowTypeLoadException(this);
return default; // Invalid kind value
}
}
return new ClassLayoutMetadata
{
Kind = layoutKind,
PackingSize = layout.PackingSize,
Size = layout.Size
Size = layout.Size,
InlineArrayLength = inlineArrayLength,
};
}
@ -578,7 +620,7 @@ namespace Internal.TypeSystem.Ecma
{
get
{
return (_typeDefinition.Attributes & TypeAttributes.ExplicitLayout) != 0;
return (_typeDefinition.Attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExplicitLayout;
}
}
@ -586,7 +628,23 @@ namespace Internal.TypeSystem.Ecma
{
get
{
return (_typeDefinition.Attributes & TypeAttributes.SequentialLayout) != 0;
return (_typeDefinition.Attributes & TypeAttributes.LayoutMask) == TypeAttributes.SequentialLayout;
}
}
public override bool IsExtendedLayout
{
get
{
return (_typeDefinition.Attributes & TypeAttributes.LayoutMask) == TypeAttributesExtendedLayout;
}
}
public override bool IsAutoLayout
{
get
{
return (_typeDefinition.Attributes & TypeAttributes.LayoutMask) == TypeAttributes.AutoLayout;
}
}

View File

@ -91,6 +91,22 @@ namespace Internal.TypeSystem.Interop
}
}
public override bool IsExtendedLayout
{
get
{
return false;
}
}
public override bool IsAutoLayout
{
get
{
return false;
}
}
public override bool IsBeforeFieldInit
{
get
@ -173,10 +189,12 @@ namespace Internal.TypeSystem.Interop
public override ClassLayoutMetadata GetClassLayout()
{
ClassLayoutMetadata result = default(ClassLayoutMetadata);
result.PackingSize = 0;
result.Size = checked((int)Length * ElementType.GetElementSize().AsInt);
return result;
return new ClassLayoutMetadata()
{
Kind = MetadataLayoutKind.Sequential,
PackingSize = 0,
Size = checked((int)Length * ElementType.GetElementSize().AsInt),
};
}
public override bool HasCustomAttribute(string attributeNamespace, string attributeName)
@ -248,12 +266,6 @@ namespace Internal.TypeSystem.Interop
return flags;
}
public override int GetInlineArrayLength()
{
Debug.Fail("when this is backed by an actual inline array, implement GetInlineArrayLength");
throw new InvalidOperationException();
}
private void InitializeMethods()
{
MethodDesc[] methods = new MethodDesc[] {

View File

@ -31,11 +31,11 @@ namespace Internal.TypeSystem.Interop
}
//
// For struct marshalling it is required to have either Sequential
// or Explicit layout. For Auto layout the P/Invoke marshalling code
// For struct marshalling it is required to not have Auto layout.
// For Auto layout the P/Invoke marshalling code
// will throw appropriate error message.
//
if (!type.HasLayout())
if (type.IsAutoLayout)
return false;
if (!type.IsValueType)

View File

@ -436,7 +436,7 @@ namespace Internal.TypeSystem.Interop
return MarshallerKind.BlittableStruct;
}
else if (((MetadataType)type).HasLayout())
else if (!((MetadataType)type).IsAutoLayout)
{
if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct)
return MarshallerKind.Invalid;
@ -642,7 +642,7 @@ namespace Internal.TypeSystem.Interop
else
return MarshallerKind.Invalid;
}
else if (type is MetadataType mdType && mdType.HasLayout())
else if (type is MetadataType mdType && !mdType.IsAutoLayout)
{
if (type.HasInstantiation)
{

View File

@ -29,7 +29,12 @@ namespace Internal.TypeSystem.Interop
var mdType = (MetadataType)type;
if (!mdType.IsSequentialLayout && !mdType.IsExplicitLayout)
if (mdType.IsExtendedLayout)
{
return mdType.GetClassLayout().Kind is MetadataLayoutKind.CStruct;
}
if (mdType.IsAutoLayout)
{
return false;
}

View File

@ -69,12 +69,6 @@ namespace Internal.TypeSystem.Interop
}
}
public override int GetInlineArrayLength()
{
Debug.Fail("if this can be an inline array, implement GetInlineArrayLength");
throw new InvalidOperationException();
}
public override bool IsSequentialLayout
{
get
@ -83,6 +77,22 @@ namespace Internal.TypeSystem.Interop
}
}
public override bool IsExtendedLayout
{
get
{
return ManagedStructType.IsExtendedLayout;
}
}
public override bool IsAutoLayout
{
get
{
return ManagedStructType.IsAutoLayout;
}
}
public override bool IsBeforeFieldInit
{
get
@ -178,7 +188,7 @@ namespace Internal.TypeSystem.Interop
Module = owningModule;
ManagedStructType = managedStructType;
_interopStateManager = interopStateManager;
_hasInvalidLayout = !managedStructType.HasLayout();
_hasInvalidLayout = managedStructType.IsAutoLayout;
_typeForFieldIteration = managedStructType.IsInlineArray ? new TypeWithRepeatedFields(managedStructType) : managedStructType;
Stack<MetadataType> typesBeingLookedAt = (s_typesBeingLookedAt ??= new Stack<MetadataType>());
@ -241,16 +251,7 @@ namespace Internal.TypeSystem.Interop
}
}
public override ClassLayoutMetadata GetClassLayout()
{
ClassLayoutMetadata layout = ManagedStructType.GetClassLayout();
ClassLayoutMetadata result;
result.PackingSize = layout.PackingSize;
result.Size = layout.Size;
return result;
}
public override ClassLayoutMetadata GetClassLayout() => ManagedStructType.GetClassLayout();
public override bool HasCustomAttribute(string attributeNamespace, string attributeName)
{

View File

@ -82,6 +82,22 @@ namespace Internal.TypeSystem.Interop
}
}
public override bool IsExtendedLayout
{
get
{
return false;
}
}
public override bool IsAutoLayout
{
get
{
return true;
}
}
public override bool IsBeforeFieldInit
{
get
@ -231,12 +247,6 @@ namespace Internal.TypeSystem.Interop
return flags;
}
public override int GetInlineArrayLength()
{
Debug.Fail("if this can be an inline array, implement GetInlineArrayLength");
throw new InvalidOperationException();
}
private MethodDesc[] _methods;
private void InitializeMethods()

View File

@ -6,7 +6,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
<SignAssembly>true</SignAssembly>
<StrongNameKeyId>Open</StrongNameKeyId>
<RunAnalyzers>false</RunAnalyzers>

View File

@ -41,20 +41,16 @@ namespace ILCompiler
protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(MetadataType type, int numInstanceFields)
{
if (type.IsExplicitLayout)
ClassLayoutMetadata layoutMetadata = type.GetClassLayout();
return layoutMetadata.Kind switch
{
return ComputeExplicitFieldLayout(type, numInstanceFields);
}
// Sequential layout has to be respected for blittable types only. We use approximation and respect it for
// all types without GC references (ie C# unmanaged types).
else if (type.IsSequentialLayout && !type.ContainsGCPointers)
{
return ComputeSequentialFieldLayout(type, numInstanceFields);
}
else
{
return ComputeAutoFieldLayout(type, numInstanceFields);
}
MetadataLayoutKind.Explicit => ComputeExplicitFieldLayout(type, numInstanceFields, layoutMetadata),
// Sequential layout has to be respected for blittable types only. We use approximation and respect it for
// all types without GC references (ie C# unmanaged types).
MetadataLayoutKind.Sequential when !type.ContainsGCPointers => ComputeSequentialFieldLayout(type, numInstanceFields, layoutMetadata),
MetadataLayoutKind.CStruct => ComputeCStructFieldLayout(type, numInstanceFields),
_ => ComputeAutoFieldLayout(type, numInstanceFields, layoutMetadata),
};
}
}
}

View File

@ -264,6 +264,8 @@ namespace ILCompiler
public override PInvokeStringFormat PInvokeStringFormat => PInvokeStringFormat.AutoClass;
public override bool IsExplicitLayout => false;
public override bool IsSequentialLayout => true;
public override bool IsExtendedLayout => true;
public override bool IsAutoLayout => false;
public override bool IsBeforeFieldInit => false;
public override MetadataType MetadataBaseType => (MetadataType)Context.GetWellKnownType(WellKnownType.Object);
public override DefType BaseType => MetadataBaseType;
@ -273,12 +275,6 @@ namespace ILCompiler
public override DefType[] ExplicitlyImplementedInterfaces => Array.Empty<DefType>();
public override TypeSystemContext Context => ValueTypeRepresented.Context;
public override int GetInlineArrayLength()
{
Debug.Fail("if this can be an inline array, implement GetInlineArrayLength");
throw new InvalidOperationException();
}
public BoxedValueType(ModuleDesc owningModule, MetadataType valuetype)
{
// BoxedValueType has the same genericness as the valuetype it's wrapping.

View File

@ -151,11 +151,7 @@ namespace ILCompiler
public override ClassLayoutMetadata GetClassLayout()
{
return new ClassLayoutMetadata
{
PackingSize = 0,
Size = 0,
};
return default;
}
public override bool HasCustomAttribute(string attributeNamespace, string attributeName)
@ -212,10 +208,20 @@ namespace ILCompiler
}
}
public override int GetInlineArrayLength()
public override bool IsExtendedLayout
{
Debug.Fail("if this can be an inline array, implement GetInlineArrayLength");
throw new InvalidOperationException();
get
{
return false;
}
}
public override bool IsAutoLayout
{
get
{
return true;
}
}
public override bool IsBeforeFieldInit
@ -226,7 +232,6 @@ namespace ILCompiler
}
}
public override DefType BaseType
{
get

View File

@ -15,6 +15,8 @@ namespace ILCompiler.Metadata
{
internal partial class Transform<TPolicy>
{
private const TypeAttributes TypeAttributesExtendedLayout = (TypeAttributes)0x00000018;
internal EntityMap<Cts.TypeDesc, MetadataRecord> _types =
new EntityMap<Cts.TypeDesc, MetadataRecord>(EqualityComparer<Cts.TypeDesc>.Default);
@ -538,6 +540,8 @@ namespace ILCompiler.Metadata
result |= TypeAttributes.ExplicitLayout;
if (type.IsSequentialLayout)
result |= TypeAttributes.SequentialLayout;
if (type.IsExtendedLayout)
result |= TypeAttributesExtendedLayout;
if (type.IsInterface)
result |= TypeAttributes.Interface;
if (type.IsSealed)

View File

@ -606,31 +606,30 @@ namespace ILCompiler
protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(MetadataType type, int numInstanceFields)
{
if (type.IsExplicitLayout)
ClassLayoutMetadata layoutMetadata = type.GetClassLayout();
MetadataLayoutKind layoutKind = layoutMetadata.Kind;
switch (layoutKind)
{
// Works around https://github.com/dotnet/runtime/issues/102868
if (!type.IsValueType &&
(type.MetadataBaseType is MetadataType baseType && baseType.IsSequentialLayout))
{
ThrowHelper.ThrowTypeLoadException(type);
}
case MetadataLayoutKind.CStruct:
return ComputeCStructFieldLayout(type, numInstanceFields);
case MetadataLayoutKind.Explicit:
// Works around https://github.com/dotnet/runtime/issues/102868
if (type is { IsValueType: false, MetadataBaseType.IsSequentialLayout: true })
{
ThrowHelper.ThrowTypeLoadException(type);
}
return ComputeExplicitFieldLayout(type, numInstanceFields);
}
else if (type.IsSequentialLayout && !type.ContainsGCPointers)
{
// Works around https://github.com/dotnet/runtime/issues/102868
if (!type.IsValueType &&
(type.MetadataBaseType is MetadataType baseType && baseType.IsExplicitLayout))
{
ThrowHelper.ThrowTypeLoadException(type);
}
return ComputeExplicitFieldLayout(type, numInstanceFields, layoutMetadata);
case MetadataLayoutKind.Sequential when !type.ContainsGCPointers:
// Works around https://github.com/dotnet/runtime/issues/102868
if (type is { IsValueType: false, MetadataBaseType.IsExplicitLayout: true })
{
ThrowHelper.ThrowTypeLoadException(type);
}
return ComputeSequentialFieldLayout(type, numInstanceFields);
}
else
{
return ComputeAutoFieldLayout(type, numInstanceFields);
return ComputeSequentialFieldLayout(type, numInstanceFields, layoutMetadata);
default:
return ComputeAutoFieldLayout(type, numInstanceFields, layoutMetadata);
}
}

View File

@ -30,17 +30,22 @@ namespace TypeSystemTests
protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(MetadataType type, int numInstanceFields)
{
if (type.IsExplicitLayout)
ClassLayoutMetadata layoutMetadata = type.GetClassLayout();
if (layoutMetadata.Kind == MetadataLayoutKind.Explicit)
{
return ComputeExplicitFieldLayout(type, numInstanceFields);
return ComputeExplicitFieldLayout(type, numInstanceFields, layoutMetadata);
}
else if (type.IsSequentialLayout || type.IsEnum)
else if (layoutMetadata.Kind == MetadataLayoutKind.Sequential || type.IsEnum)
{
return ComputeSequentialFieldLayout(type, numInstanceFields);
return ComputeSequentialFieldLayout(type, numInstanceFields, layoutMetadata);
}
else if (layoutMetadata.Kind == MetadataLayoutKind.CStruct)
{
return ComputeCStructFieldLayout(type, numInstanceFields);
}
else
{
return ComputeAutoFieldLayout(type, numInstanceFields);
return ComputeAutoFieldLayout(type, numInstanceFields, layoutMetadata);
}
}
}

View File

@ -148,6 +148,10 @@ namespace Microsoft.Diagnostics.Tools.Pgo.TypeRefTypeSystem
public override bool IsSequentialLayout => throw new NotImplementedException();
public override bool IsExtendedLayout => throw new NotImplementedException();
public override bool IsAutoLayout => throw new NotImplementedException();
public override bool IsBeforeFieldInit => throw new NotImplementedException();
public override ModuleDesc Module => _module;
@ -251,11 +255,5 @@ namespace Microsoft.Diagnostics.Tools.Pgo.TypeRefTypeSystem
}
protected override MethodImplRecord[] ComputeVirtualMethodImplsForType() => throw new NotImplementedException();
public override int GetInlineArrayLength()
{
Debug.Fail("if this can be an inline array, implement GetInlineArrayLength");
throw new InvalidOperationException();
}
}
}

View File

@ -338,7 +338,8 @@ class EEClassLayoutInfo
{
Auto = 0, // Make sure Auto is the default value as the default-constructed value represents the "auto layout" case
Sequential,
Explicit
Explicit,
CStruct
};
private:
enum {
@ -486,6 +487,12 @@ class EEClassLayoutInfo
mdTypeDef cl
);
ULONG InitializeCStructFieldLayout(
FieldDesc* pFields,
MethodTable** pByValueClassCache,
ULONG cFields
);
private:
void SetIsZeroSized(BOOL isZeroSized)
{

View File

@ -607,6 +607,35 @@ ULONG EEClassLayoutInfo::InitializeExplicitFieldLayout(
return SetInstanceBytesSize(managedSize);
}
ULONG EEClassLayoutInfo::InitializeCStructFieldLayout(
FieldDesc* pFields,
MethodTable** pByValueClassCache,
ULONG cFields
)
{
STANDARD_VM_CONTRACT;
SetLayoutType(LayoutType::CStruct);
NewArrayHolder<LayoutRawFieldInfo> pInfoArray = new LayoutRawFieldInfo[cFields + 1];
UINT32 numInstanceFields;
BYTE fieldsAlignmentRequirement;
InitializeLayoutFieldInfoArray(pFields, cFields, pByValueClassCache, DEFAULT_PACKING_SIZE, pInfoArray, &numInstanceFields, &fieldsAlignmentRequirement);
BYTE alignmentRequirement = max<BYTE>(1, fieldsAlignmentRequirement);
SetAlignmentRequirement(alignmentRequirement);
SetPackingSize(DEFAULT_PACKING_SIZE);
UINT32 lastFieldEnd = CalculateOffsetsForSequentialLayout(pInfoArray, numInstanceFields, 0, DEFAULT_PACKING_SIZE);
SetFieldOffsets(pFields, cFields, pInfoArray, numInstanceFields);
UINT32 managedSize = AlignSize(lastFieldEnd, alignmentRequirement);
return SetInstanceBytesSize(managedSize);
}
namespace
{
#ifdef UNIX_AMD64_ABI

View File

@ -140,10 +140,6 @@ MethodTableBuilder::CreateClass( Module *pModule,
pEEClass->m_dwAttrClass = dwAttrClass;
// MDVal check: can't be both tdSequentialLayout and tdExplicitLayout
if((dwAttrClass & tdLayoutMask) == tdLayoutMask)
COMPlusThrowHR(COR_E_TYPELOAD);
if (IsTdInterface(dwAttrClass))
{
// MDVal check: must have nil tkExtends and must be tdAbstract
@ -8276,6 +8272,27 @@ VOID MethodTableBuilder::PlaceInstanceFields(MethodTable** pByValueClassCache)
case EEClassLayoutInfo::LayoutType::Explicit:
HandleExplicitLayout(pByValueClassCache);
break;
case EEClassLayoutInfo::LayoutType::CStruct:
{
if (!pParentMT->IsValueTypeClass()
|| hasGCFields
|| isAutoLayoutOrHasAutoLayoutField)
{
// CStruct layout types can't have a parent type, GC fields
// or auto layout fields.
BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
}
// Explicit size is not used for CStruct layout.
pLayoutInfo->SetHasExplicitSize(FALSE);
// CStruct layouts are always blittable
pLayoutInfo->SetIsBlittable(TRUE);
HandleCStructLayout(pByValueClassCache);
break;
}
default:
UNREACHABLE();
break;
@ -8739,6 +8756,33 @@ VOID MethodTableBuilder::HandleExplicitLayout(MethodTable** pByValueClassCache)
}
}
VOID MethodTableBuilder::HandleCStructLayout(MethodTable** pByValueClassCache)
{
STANDARD_VM_CONTRACT;
_ASSERTE(HasLayout());
EEClassLayoutInfo* pLayoutInfo = GetLayoutInfo();
CONSISTENCY_CHECK(pLayoutInfo != nullptr);
bmtFP->NumInstanceFieldBytes = pLayoutInfo->InitializeCStructFieldLayout(
GetHalfBakedClass()->GetFieldDescList(),
pByValueClassCache,
bmtEnumFields->dwNumDeclaredFields
);
if (bmtFP->NumInlineArrayElements != 0)
{
BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
}
if (pLayoutInfo->IsZeroSized())
{
BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
}
}
//*******************************************************************************
// this accesses the field size which is temporarily stored in m_pMTOfEnclosingClass
// during class loading. Don't use any other time
@ -12415,7 +12459,7 @@ MethodTableBuilder::GatherGenericsInfo(
// *pPackingSize declared packing size
// *pfExplicitoffsets offsets explicit in metadata or computed?
//=======================================================================
BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport, mdTypeDef cl, MethodTable* pParentMT, BYTE* pPackingSize, ULONG* pClassSize, CorNativeLinkType* pNLTType, BOOL* pfExplicitOffsets)
BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport, mdTypeDef cl, MethodTable* pParentMT, BYTE* pPackingSize, ULONG* pClassSize, CorNativeLinkType* pNLTType, EEClassLayoutInfo::LayoutType* pLayoutType)
{
CONTRACTL
{
@ -12426,7 +12470,7 @@ BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport,
PRECONDITION(CheckPointer(pPackingSize));
PRECONDITION(CheckPointer(pClassSize));
PRECONDITION(CheckPointer(pNLTType));
PRECONDITION(CheckPointer(pfExplicitOffsets));
PRECONDITION(CheckPointer(pLayoutType));
}
CONTRACTL_END;
@ -12439,15 +12483,53 @@ BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport,
if (IsTdAutoLayout(clFlags))
{
*pLayoutType = EEClassLayoutInfo::LayoutType::Auto;
return FALSE;
}
else if (IsTdSequentialLayout(clFlags))
{
*pfExplicitOffsets = FALSE;
*pLayoutType = EEClassLayoutInfo::LayoutType::Sequential;
}
else if (IsTdExplicitLayout(clFlags))
{
*pfExplicitOffsets = TRUE;
*pLayoutType = EEClassLayoutInfo::LayoutType::Explicit;
}
else if (IsTdExtendedLayout(clFlags))
{
const void* pVal; // The custom value.
ULONG cbVal; // Size of the custom value.
HRESULT hr = pInternalImport->GetCustomAttributeByName(
cl,
GetWellKnownAttributeName(WellKnownAttribute::ExtendedLayoutAttribute),
&pVal, &cbVal);
if (hr == S_FALSE)
{
pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
}
if (cbVal < (sizeof(INT32) + 2))
{
pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
}
CustomAttributeParser parser(pVal, cbVal);
IfFailThrow(parser.ValidateProlog());
int32_t kindValue;
IfFailThrow(parser.GetI4(&kindValue));
CorExtendedLayoutKind kind = (CorExtendedLayoutKind)kindValue;
if (kind == CorExtendedLayoutKind::CStruct)
{
*pLayoutType = EEClassLayoutInfo::LayoutType::CStruct;
}
else
{
pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
}
}
else
{
@ -12595,7 +12677,6 @@ ClassLoader::CreateTypeHandleForTypeDefThrowing(
GetEnclosingClassThrowing(pInternalImport, pModule, cl, &tdEnclosing);
BOOL fExplicitOffsets = FALSE;
MethodTableBuilder::bmtLayoutInfo layoutInfo;
// NOTE: HasLayoutMetadata does not load classes
BOOL fHasLayout =
@ -12608,18 +12689,8 @@ ClassLoader::CreateTypeHandleForTypeDefThrowing(
&layoutInfo.packingSize,
&layoutInfo.classSize,
&layoutInfo.nlFlags,
&fExplicitOffsets);
&layoutInfo.layoutType);
if (fHasLayout)
{
layoutInfo.layoutType = fExplicitOffsets
? EEClassLayoutInfo::LayoutType::Explicit
: EEClassLayoutInfo::LayoutType::Sequential;
}
else
{
layoutInfo.layoutType = EEClassLayoutInfo::LayoutType::Auto;
}
BOOL fIsEnum = ((g_pEnumClass != NULL) && (pParentMethodTable == g_pEnumClass));

View File

@ -3001,6 +3001,9 @@ private:
VOID HandleGCForExplicitLayout();
VOID HandleCStructLayout(
MethodTable **);
VOID CheckForHFA(MethodTable ** pByValueClassCache);
VOID CheckForNativeHFA();

View File

@ -37,6 +37,7 @@ enum class WellKnownAttribute : DWORD
InlineArrayAttribute,
UnsafeAccessorAttribute,
UnsafeAccessorTypeAttribute,
ExtendedLayoutAttribute,
CountOfWellKnownAttributes
};
@ -141,6 +142,9 @@ inline const char *GetWellKnownAttributeName(WellKnownAttribute attribute)
case WellKnownAttribute::UnsafeAccessorTypeAttribute:
ret = "System.Runtime.CompilerServices.UnsafeAccessorTypeAttribute";
break;
case WellKnownAttribute::ExtendedLayoutAttribute:
ret = "System.Runtime.InteropServices.ExtendedLayoutAttribute";
break;
case WellKnownAttribute::CountOfWellKnownAttributes:
default:
ret = nullptr;

View File

@ -979,6 +979,8 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\DllImportAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\DllImportSearchPath.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\ErrorWrapper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\ExtendedLayoutAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\ExtendedLayoutKind.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\ExternalException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\FieldOffsetAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\GCHandle.cs" />

View File

@ -18,11 +18,11 @@ namespace System.Reflection
NestedFamORAssem = 0x00000007, // Class is nested with family or assembly visibility.
// Use this mask to retrieve class layout information
// 0 is AutoLayout, 0x2 is SequentialLayout, 4 is ExplicitLayout
LayoutMask = 0x00000018,
AutoLayout = 0x00000000, // Class fields are auto-laid out
SequentialLayout = 0x00000008, // Class fields are laid out sequentially
ExplicitLayout = 0x00000010, // Layout is supplied explicitly
ExtendedLayout = 0x00000018, // Layout is supplied via the System.Runtime.InteropServices.ExtendedLayoutAttribute
// end layout mask
// Use this mask to distinguish whether a type declaration is an interface. (Class vs. ValueType done based on whether it subclasses S.ValueType)

View File

@ -0,0 +1,20 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Runtime.InteropServices
{
/// <summary>
/// Indicates the layout rules for a value type at runtime.
/// </summary>
[AttributeUsage(AttributeTargets.Struct, Inherited = false)]
public sealed class ExtendedLayoutAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="ExtendedLayoutAttribute"/> class with the specified layout kind.
/// </summary>
/// <param name="layoutKind">The layout algorithm to use for this value type.</param>
public ExtendedLayoutAttribute(ExtendedLayoutKind layoutKind)
{
}
}
}

View File

@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Runtime.InteropServices
{
/// <summary>
/// Indicates the layout kind of a struct when using extended layout.
/// </summary>
public enum ExtendedLayoutKind
{
/// <summary>
/// The value type should have its fields laid out in accordance with the C language struct layout rules.
/// </summary>
CStruct = 0,
}
}

View File

@ -7,6 +7,7 @@ namespace System.Runtime.InteropServices
public enum LayoutKind
{
Sequential = 0,
Extended = 1,
Explicit = 2,
Auto = 3,
}

View File

@ -503,6 +503,7 @@ namespace System.Reflection.Emit
LayoutKind.Auto => TypeAttributes.AutoLayout,
LayoutKind.Explicit => TypeAttributes.ExplicitLayout,
LayoutKind.Sequential => TypeAttributes.SequentialLayout,
LayoutKind.Extended => TypeAttributes.ExtendedLayout,
_ => TypeAttributes.AutoLayout,
};

View File

@ -40,7 +40,6 @@ namespace System.Reflection.Emit.Tests
[ActiveIssue("https://github.com/dotnet/runtime/issues/2389", TestRuntimes.Mono)]
[InlineData(TypeAttributes.ClassSemanticsMask)]
[InlineData(TypeAttributes.HasSecurity)]
[InlineData(TypeAttributes.LayoutMask)]
[InlineData(TypeAttributes.NestedAssembly)]
[InlineData(TypeAttributes.NestedFamANDAssem)]
[InlineData(TypeAttributes.NestedFamily)]

View File

@ -53,7 +53,6 @@ namespace System.Reflection.Emit.Tests
[ActiveIssue("https://github.com/dotnet/runtime/issues/2389", TestRuntimes.Mono)]
[InlineData(TypeAttributes.ClassSemanticsMask, typeof(InvalidOperationException))]
[InlineData(TypeAttributes.HasSecurity, typeof(ArgumentException))]
[InlineData(TypeAttributes.LayoutMask, typeof(ArgumentException))]
[InlineData(TypeAttributes.NestedAssembly, typeof(ArgumentException))]
[InlineData(TypeAttributes.NestedFamANDAssem, typeof(ArgumentException))]
[InlineData(TypeAttributes.NestedFamily, typeof(ArgumentException))]

View File

@ -155,8 +155,6 @@ namespace System.Reflection.Emit.Tests
[InlineData(TypeAttributes.Public, "attr")]
[InlineData(TypeAttributes.NotPublic, "attr")]
[InlineData(TypeAttributes.Interface, "attr")]
[InlineData(TypeAttributes.LayoutMask, "attr")]
[InlineData(TypeAttributes.LayoutMask | TypeAttributes.Public, "attr")]
[InlineData((TypeAttributes)0x00040800, "attr")]
[InlineData((TypeAttributes)(-1), null)]
[InlineData((TypeAttributes)(-5000), "attr")]

View File

@ -143,6 +143,9 @@ namespace System.Reflection.TypeLoading
}
}
private const TypeAttributes TypeAttributesExtendedLayout = (TypeAttributes)0x00000018; // TypeAttributes.ExtendedLayout
private const LayoutKind LayoutKindExtended = (LayoutKind)1;
public sealed override StructLayoutAttribute? StructLayoutAttribute
{
get
@ -158,6 +161,7 @@ namespace System.Reflection.TypeLoading
TypeAttributes.ExplicitLayout => LayoutKind.Explicit,
TypeAttributes.AutoLayout => LayoutKind.Auto,
TypeAttributes.SequentialLayout => LayoutKind.Sequential,
TypeAttributesExtendedLayout => LayoutKindExtended,
_ => LayoutKind.Auto,
};
CharSet charSet = (attributes & TypeAttributes.StringFormatMask) switch

View File

@ -12805,6 +12805,7 @@ namespace System.Reflection
VisibilityMask = 7,
SequentialLayout = 8,
ExplicitLayout = 16,
ExtendedLayout = 24,
LayoutMask = 24,
ClassSemanticsMask = 32,
Interface = 32,
@ -14223,6 +14224,16 @@ namespace System.Runtime.InteropServices
protected void SetHandle(System.IntPtr handle) { }
public void SetHandleAsInvalid() { }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Struct, Inherited=false)]
public sealed class ExtendedLayoutAttribute : System.Attribute
{
public ExtendedLayoutAttribute(System.Runtime.InteropServices.ExtendedLayoutKind layoutKind) { }
}
public enum ExtendedLayoutKind
{
CStruct = 0,
}
public partial class ExternalException : System.SystemException
{
public ExternalException() { }
@ -14304,6 +14315,7 @@ namespace System.Runtime.InteropServices
public enum LayoutKind
{
Sequential = 0,
Extended = 1,
Explicit = 2,
Auto = 3,
}

View File

@ -1303,6 +1303,7 @@ namespace System.Reflection.Emit
LayoutKind.Auto => TypeAttributes.AutoLayout,
LayoutKind.Explicit => TypeAttributes.ExplicitLayout,
LayoutKind.Sequential => TypeAttributes.SequentialLayout,
LayoutKind.Extended => TypeAttributes.ExtendedLayout,
_ => throw new Exception(SR.Argument_InvalidKindOfTypeForCA), // we should ignore it since it can be any value anyway...
};

View File

@ -2575,6 +2575,7 @@ namespace System
case TypeAttributes.ExplicitLayout: layoutKind = LayoutKind.Explicit; break;
case TypeAttributes.AutoLayout: layoutKind = LayoutKind.Auto; break;
case TypeAttributes.SequentialLayout: layoutKind = LayoutKind.Sequential; break;
case TypeAttributes.ExtendedLayout: layoutKind = LayoutKind.Extended; break;
default: break;
}

View File

@ -31,6 +31,7 @@ typedef enum {
PROP_FIELD_DEF_VALUES_8BYTESWIZZLE = 13, /* MonoFieldDefaultValue* with default values swizzled at 8 byte boundaries*/
PROP_METADATA_UPDATE_INFO = 14, /* MonoClassMetadataUpdateInfo* */
PROP_INLINEARRAY_VALUE = 15, /* System.Runtime.CompilerServices.InlineArrayAttribute length value */
PROP_EXTENDEDLAYOUT_VALUE = 16, /* System.Runtime.CompilerServices.ExtendedLayoutAttribute value */
} InfrequentDataKind;
/* Accessors based on class kind*/
@ -701,6 +702,22 @@ mono_class_set_inlinearray_value (MonoClass *klass, gint32 value)
mono_property_bag_add (m_class_get_infrequent_data (klass), prop);
}
gint32
mono_class_get_extendedlayout_value (MonoClass *klass)
{
Uint32Property *prop = (Uint32Property*)mono_property_bag_get (m_class_get_infrequent_data (klass), PROP_EXTENDEDLAYOUT_VALUE);
return prop ? prop->value : 0;
}
void
mono_class_set_extendedlayout_value (MonoClass *klass, gint32 kind)
{
Uint32Property *prop = (Uint32Property*)mono_class_alloc (klass, sizeof (Uint32Property));
prop->head.tag = PROP_EXTENDEDLAYOUT_VALUE;
prop->value = kind;
mono_property_bag_add (m_class_get_infrequent_data (klass), prop);
}
#ifdef MONO_CLASS_DEF_PRIVATE
#define MONO_CLASS_GETTER(funcname, rettype, optref, argtype, fieldname) rettype funcname (argtype *klass) { return optref klass-> fieldname ; }
#define MONO_CLASS_OFFSET(funcname, argtype, fieldname) intptr_t funcname (void) { return MONO_STRUCT_OFFSET (argtype, fieldname); }

View File

@ -67,6 +67,7 @@ static int generic_array_methods (MonoClass *klass);
static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache);
static FoundAttrUD class_has_isbyreflike_attribute (MonoClass *klass);
static FoundAttrUD class_has_inlinearray_attribute (MonoClass *klass);
static FoundAttrUD class_has_extendedlayout_attribute (MonoClass *klass);
static
GENERATE_TRY_GET_CLASS_WITH_CACHE(icollection, "System.Collections.Generic", "ICollection`1");
@ -744,6 +745,24 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
klass->is_inlinearray = 1;
mono_class_set_inlinearray_value(klass, GPOINTER_TO_INT32 (attr.value));
}
if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXTENDED_LAYOUT) {
attr = class_has_extendedlayout_attribute (klass);
if (attr.has_attr) {
mono_class_set_extendedlayout_value (klass, GPOINTER_TO_INT32 (attr.value));
} else {
mono_class_set_type_load_failure (klass, "Extended layout attribute not found for %s", m_class_get_name (klass));
mono_loader_unlock ();
MONO_PROFILER_RAISE (class_failed, (klass));
return NULL;
}
if (klass->is_inlinearray) {
mono_class_set_type_load_failure (klass, "InlineArray type %s cannot have extended layout.", m_class_get_name (klass));
mono_loader_unlock ();
MONO_PROFILER_RAISE (class_failed, (klass));
return NULL;
}
}
}
// compute is_exception_class, used by interp to avoid inlining exception handling code
@ -838,6 +857,25 @@ has_inline_array_attribute_value_func (MonoImage *image, uint32_t method_token,
}
}
static void
has_extended_layout_attribute_value_func (MonoImage *image, uint32_t method_token, uint32_t *cols, gpointer user_data)
{
FoundAttrUD *attr = (FoundAttrUD *)user_data;
MonoError error;
MonoMethod *ctor = mono_get_method_checked (image, method_token, NULL, NULL, &error);
if (ctor) {
const char *data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
uint32_t data_size = mono_metadata_decode_value (data, &data);
MonoDecodeCustomAttr *decoded_attr = mono_reflection_create_custom_attr_data_args_noalloc (image, ctor, (guchar*)data, data_size, &error);
mono_error_assert_ok (&error);
g_assert (decoded_attr->named_args_num == 0 && decoded_attr->typed_args_num == 1);
attr->value = GUINT_TO_POINTER (*(guint32 *)decoded_attr->typed_args [0]->value.primitive);
g_free (decoded_attr);
} else {
g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, method_token, mono_error_get_message (&error));
}
}
static FoundAttrUD
class_has_wellknown_attribute (MonoClass *klass, const char *nspace, const char *name, gboolean in_corlib, gboolean has_value, MonoHasValueCallback callback)
{
@ -883,6 +921,11 @@ class_has_inlinearray_attribute (MonoClass *klass)
return class_has_wellknown_attribute (klass, "System.Runtime.CompilerServices", "InlineArrayAttribute", TRUE, TRUE, has_inline_array_attribute_value_func);
}
static FoundAttrUD
class_has_extendedlayout_attribute (MonoClass *klass)
{
return class_has_wellknown_attribute (klass, "System.Runtime.InteropServices", "ExtendedLayoutAttribute", TRUE, TRUE, has_extended_layout_attribute_value_func);
}
gboolean
mono_class_setup_method_has_preserve_base_overrides_attribute (MonoMethod *method)
@ -2063,6 +2106,10 @@ validate_struct_fields_overlaps (guint8 *layout_check, int layout_size, MonoClas
return TRUE;
}
typedef enum _ExtendedLayoutKind {
EXTENDED_LAYOUT_KIND_CSTRUCT = 0
} ExtendedLayoutKind;
/*
* mono_class_layout_fields:
* @class: a class
@ -2432,6 +2479,89 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
}
break;
}
case TYPE_ATTRIBUTE_EXTENDED_LAYOUT: {
ExtendedLayoutKind extended_layout_kind = (ExtendedLayoutKind)mono_class_get_extendedlayout_value (klass);
if (extended_layout_kind == EXTENDED_LAYOUT_KIND_CSTRUCT) {
if (!m_class_is_valuetype(klass)) {
if (mono_class_set_type_load_failure (klass, "CStruct type must be value type."))
return;
}
mono_class_setup_fields (klass->parent);
if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
return;
real_size = klass->parent->instance_size;
if (top == 0) {
/* Empty structs are not allowed */
if (mono_class_set_type_load_failure (klass, "CStruct type cannot be empty."))
return;
}
if (any_field_has_auto_layout) {
if (mono_class_set_type_load_failure (klass, "CStruct type cannot have AutoLayout fields."))
return;
}
klass->blittable = TRUE;
for (i = 0; i < top; i++){
gint32 align;
guint32 size;
MonoType *ftype;
field = &klass->fields [i];
if (mono_field_is_deleted (field))
continue;
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
continue;
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
if ((top == 1) && (instance_size == MONO_ABI_SIZEOF (MonoObject)) &&
(strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
/* This field is a hack inserted by MCS to empty structures */
continue;
}
size = mono_type_size (field->type, &align);
if (type_has_references (klass, ftype))
if (mono_class_set_type_load_failure (klass, "CStruct type must not have reference fields."))
return;
min_align = MAX (align, min_align);
field_offsets [i] = real_size;
if (align) {
field_offsets [i] += align - 1;
field_offsets [i] &= ~(align - 1);
}
/*TypeBuilders produce all sort of weird things*/
g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
gint64 raw_real_size = (gint64)field_offsets [i] + size;
real_size = (gint32)raw_real_size;
if (real_size != raw_real_size)
mono_class_set_type_load_failure (klass, "Can't load type %s. The size is too big.", m_class_get_name (klass));
}
instance_size = real_size;
if (instance_size & (min_align - 1)) {
instance_size += min_align - 1;
instance_size &= ~(min_align - 1);
}
break;
}
else {
mono_class_set_type_load_failure (klass, "Unknown extended layout kind '%d'.", extended_layout_kind);
return;
}
}
}
if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {

View File

@ -1357,6 +1357,12 @@ mono_class_get_inlinearray_value (MonoClass *klass);
void
mono_class_set_inlinearray_value (MonoClass *klass, gint32 value);
MONO_COMPONENT_API gint32
mono_class_get_extendedlayout_value (MonoClass *klass);
void
mono_class_set_extendedlayout_value (MonoClass *klass, gint32 value);
void
mono_class_set_weak_bitmap (MonoClass *klass, int nbits, gsize *bits);

View File

@ -5943,62 +5943,39 @@ mono_marshal_is_loading_type_info (MonoClass *klass)
return g_slist_find (loads_list, klass) != NULL;
}
/**
* mono_marshal_load_type_info:
*
* Initialize \c klass::marshal_info using information from metadata. This function can
* recursively call itself, and the caller is responsible to avoid that by calling
* \c mono_marshal_is_loading_type_info beforehand.
*
* LOCKING: Acquires the loader lock.
*/
MonoMarshalType *
mono_marshal_load_type_info (MonoClass* klass)
static void
mono_marshal_load_extended_layout_type_info(MonoClass* klass, MonoMarshalType* info)
{
int j, count = 0;
guint32 native_size = 0, min_align = 1, packing, explicit_size = 0;
MonoMarshalType *info;
int j = 0;
gpointer iter = NULL;
MonoClassField* field;
gpointer iter;
guint32 layout;
GSList *loads_list;
g_assert (klass != NULL);
info = mono_class_get_marshal_info (klass);
if (info)
return info;
if (!m_class_is_inited (klass))
mono_class_init_internal (klass);
info = mono_class_get_marshal_info (klass);
if (info)
return info;
/*
* This function can recursively call itself, so we keep the list of classes which are
* under initialization in a TLS list.
*/
g_assert (!mono_marshal_is_loading_type_info (klass));
loads_list = (GSList *)mono_native_tls_get_value (load_type_info_tls_id);
loads_list = g_slist_prepend (loads_list, klass);
mono_native_tls_set_value (load_type_info_tls_id, loads_list);
iter = NULL;
info->native_size = mono_class_instance_size(klass) - MONO_ABI_SIZEOF (MonoObject);
info->min_align = mono_class_min_align(klass);
while ((field = mono_class_get_fields_internal (klass, &iter))) {
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
continue;
if (mono_field_is_deleted (field))
continue;
count++;
info->fields [j].field = field;
info->fields [j].offset = mono_field_get_offset (field);
}
}
static void
mono_marshal_load_standard_layout_type_info(MonoClass* klass, MonoMarshalType* info)
{
int j;
guint32 native_size = 0, min_align = 1, packing, explicit_size = 0;
MonoClassField* field;
gpointer iter;
guint32 layout;
layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
info = (MonoMarshalType *)mono_image_alloc0 (m_class_get_image (klass), MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count);
info->num_fields = count;
/* Try to find a size for this type in metadata */
explicit_size = mono_metadata_packing_from_typedef (m_class_get_image (klass), m_class_get_type_token (klass), NULL, &native_size);
@ -6108,6 +6085,70 @@ mono_marshal_load_type_info (MonoClass* klass)
if (m_class_get_rank (klass) && !mono_marshal_is_loading_type_info (m_class_get_element_class (klass))) {
mono_marshal_load_type_info (m_class_get_element_class (klass));
}
}
/**
* mono_marshal_load_type_info:
*
* Initialize \c klass::marshal_info using information from metadata. This function can
* recursively call itself, and the caller is responsible to avoid that by calling
* \c mono_marshal_is_loading_type_info beforehand.
*
* LOCKING: Acquires the loader lock.
*/
MonoMarshalType *
mono_marshal_load_type_info (MonoClass* klass)
{
int count = 0;
MonoMarshalType *info;
MonoClassField* field;
gpointer iter;
guint32 layout;
GSList *loads_list;
g_assert (klass != NULL);
info = mono_class_get_marshal_info (klass);
if (info)
return info;
if (!m_class_is_inited (klass))
mono_class_init_internal (klass);
info = mono_class_get_marshal_info (klass);
if (info)
return info;
/*
* This function can recursively call itself, so we keep the list of classes which are
* under initialization in a TLS list.
*/
g_assert (!mono_marshal_is_loading_type_info (klass));
loads_list = (GSList *)mono_native_tls_get_value (load_type_info_tls_id);
loads_list = g_slist_prepend (loads_list, klass);
mono_native_tls_set_value (load_type_info_tls_id, loads_list);
iter = NULL;
while ((field = mono_class_get_fields_internal (klass, &iter))) {
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
continue;
if (mono_field_is_deleted (field))
continue;
count++;
}
info = (MonoMarshalType *)mono_image_alloc0 (m_class_get_image (klass), MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count);
info->num_fields = count;
layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
if (layout == TYPE_ATTRIBUTE_EXTENDED_LAYOUT) {
mono_marshal_load_extended_layout_type_info(klass, info);
} else {
mono_marshal_load_standard_layout_type_info(klass, info);
}
loads_list = (GSList *)mono_native_tls_get_value (load_type_info_tls_id);
loads_list = g_slist_remove (loads_list, klass);

View File

@ -116,6 +116,7 @@ enum {
#define TYPE_ATTRIBUTE_AUTO_LAYOUT 0x00000000
#define TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT 0x00000008
#define TYPE_ATTRIBUTE_EXPLICIT_LAYOUT 0x00000010
#define TYPE_ATTRIBUTE_EXTENDED_LAYOUT 0x00000018
#define TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK 0x00000020
#define TYPE_ATTRIBUTE_CLASS 0x00000000

View File

@ -0,0 +1,105 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Xunit;
namespace ExtendedLayoutTests;
public static class CStructTests
{
[Fact]
public static void BlittablePrimitiveFieldsLayout()
{
var c = default(CStructBlittablePrimitiveFields);
Assert.Equal(12, Unsafe.SizeOf<CStructBlittablePrimitiveFields>());
Assert.Equal(0, Unsafe.ByteOffset(ref Unsafe.As<CStructBlittablePrimitiveFields, byte>(ref c), ref Unsafe.As<int, byte>(ref c.a)));
Assert.Equal(4, Unsafe.ByteOffset(ref Unsafe.As<CStructBlittablePrimitiveFields, byte>(ref c), ref Unsafe.As<float, byte>(ref c.b)));
Assert.Equal(8, Unsafe.ByteOffset(ref Unsafe.As<CStructBlittablePrimitiveFields, byte>(ref c), ref c.c));
}
[Fact]
public static void NonBlittableUnmanagedPrimitiveFields_TreatedAsBlittable()
{
var c = default(CStructNonBlittablePrimitiveFields);
Assert.Equal(Unsafe.SizeOf<CStructNonBlittablePrimitiveFields>(), Marshal.SizeOf<CStructNonBlittablePrimitiveFields>());
Assert.Equal(4, Unsafe.SizeOf<CStructNonBlittablePrimitiveFields>());
Assert.Equal(0, Unsafe.ByteOffset(ref Unsafe.As<CStructNonBlittablePrimitiveFields, byte>(ref c), ref Unsafe.As<bool, byte>(ref c.b)));
Assert.Equal(2, Unsafe.ByteOffset(ref Unsafe.As<CStructNonBlittablePrimitiveFields, byte>(ref c), ref Unsafe.As<char, byte>(ref c.c)));
}
[Fact]
public static void ReferenceFields_ThrowTypeLoadException()
{
Assert.Throws<TypeLoadException>(() => typeof(CStructWithReferenceFields));
Assert.Throws<TypeLoadException>(() => typeof(CStructWithMixedFields));
}
[Fact]
public static void NestedCStruct()
{
var nested = new CStructCustomCStructField
{
y = new NestedCStructType
{
x = 42
}
};
Assert.Equal(4, Unsafe.SizeOf<CStructCustomCStructField>());
}
[Fact]
public static void NestedNonCStructNonAuto()
{
var nested = new CStructCustomSeqStructField
{
y = new NestedSequentialType
{
x = 42
}
};
Assert.Equal(4, Unsafe.SizeOf<CStructCustomSeqStructField>());
}
[Fact]
public static void NestedAutoLayout_ThrowTypeLoadException()
{
Assert.Throws<TypeLoadException>(() => typeof(CStructCustomAutoStructField));
}
[Fact]
public static void EmptyStruct()
{
Assert.Throws<TypeLoadException>(() => typeof(EmptyCStruct));
}
[Fact]
public static void ExplicitOffsets_Ignored()
{
CStructWithOffsets c = default;
Assert.Equal(0, Unsafe.ByteOffset(ref Unsafe.As<CStructWithOffsets, byte>(ref c), ref Unsafe.As<int, byte>(ref c.a)));
}
[Fact]
public static void ExplicitSize_Ignored()
{
Assert.Equal(4, Unsafe.SizeOf<CStructWithSize>());
}
[Fact]
public static void Pack_Ignored()
{
Assert.Equal(8, Unsafe.SizeOf<CStructWithPack>());
CStructWithPack c = default;
Assert.Equal(4, Unsafe.ByteOffset(ref Unsafe.As<CStructWithPack, byte>(ref c), ref Unsafe.As<int, byte>(ref c.b)));
}
}

View File

@ -0,0 +1,30 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Xunit;
namespace ExtendedLayoutTests;
public static class ExtendedLayout
{
[Fact]
public static void ExtendedLayout_NoExtendedLayoutAttribute()
{
Assert.Throws<TypeLoadException>(() => typeof(NoExtendedAttributeOnType));
}
[Fact]
public static void ExtendedLayout_InvalidKind()
{
Assert.Throws<TypeLoadException>(() => typeof(ExtendedLayoutInvalidKind));
}
[Fact]
public static void ExtendedLayout_InlineArray_Invalid()
{
Assert.Throws<TypeLoadException>(() => typeof(InlineArrayOnExtendedLayout));
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="ExtendedLayout.cs" />
<Compile Include="CStruct.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="ExtendedLayoutTypes.ilproj" />
<ProjectReference Include="$(TestLibraryProjectPath)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,160 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
.assembly extern System.Runtime { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) }
.assembly ExtendedLayoutTypes { }
// Invalid type examples
.class flags(0x18) public value beforefieldinit NoExtendedAttributeOnType
{
.field public int32 a
}
.class flags(0x18) public value beforefieldinit InlineArrayOnExtendedLayout
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.custom instance void [System.Runtime]System.Runtime.CompilerServices.InlineArrayAttribute::.ctor(int32) = {
int32(0x00000004)
}
.field public int32 a
}
.class flags(0x18) public value beforefieldinit ExtendedLayoutInvalidKind
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(-2) // Unknown kind
}
.field public int32 a
}
// CStruct types below (can be moved to C# once we have ExtendedLayout support in the C# compiler)
.class flags(0x18) public value beforefieldinit CStructBlittablePrimitiveFields
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field public int32 a
.field public float32 b
.field public uint8 c
}
.class flags(0x18) public value beforefieldinit CStructNonBlittablePrimitiveFields
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field public bool b
.field public char c
}
.class flags(0x18) public value beforefieldinit CStructWithReferenceFields
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field public class [System.Runtime]System.String a
}
.class flags(0x18) public value beforefieldinit CStructWithMixedFields
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field public int32 a
.field public class [System.Runtime]System.String b
}
.class flags(0x18) public value beforefieldinit NestedCStructType
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field public int32 x
}
.class flags(0x18) public value beforefieldinit CStructCustomCStructField
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field public valuetype NestedCStructType y
}
.class public sequential value beforefieldinit NestedSequentialType
{
.field public int32 x
}
.class flags(0x18) public value beforefieldinit CStructCustomSeqStructField
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field public valuetype NestedSequentialType y
}
.class public auto value beforefieldinit NestedAutoLayoutType
{
.field public int32 x
}
.class flags(0x18) public value beforefieldinit CStructCustomAutoStructField
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field public valuetype NestedAutoLayoutType y
}
.class flags(0x18) public value beforefieldinit EmptyCStruct
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
}
.class flags(0x18) public value beforefieldinit CStructWithOffsets
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field [4] public int32 a
}
.class flags(0x18) public value beforefieldinit CStructWithSize
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field public int32 a
.size 12
}
.class flags(0x18) public value beforefieldinit CStructWithPack
{
.custom instance void [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutAttribute::.ctor(valuetype [System.Runtime]System.Runtime.InteropServices.ExtendedLayoutKind) = {
int32(0x00000000) // CStruct
}
.field public int8 a
.field public int32 b
.pack 1
}

View File

@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk.IL">
<PropertyGroup>
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<Compile Include="ExtendedLayoutTypes.il" />
</ItemGroup>
</Project>