mirror of https://github.com/dotnet/runtime
Merge 62ca1b5d63
into 02596ba8d9
This commit is contained in:
commit
b322344c93
|
@ -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 type’s 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 type’s 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 |
|
||||
|
||||
|
|
|
@ -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))" />
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
@ -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 ");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace System.Runtime.InteropServices
|
|||
public enum LayoutKind
|
||||
{
|
||||
Sequential = 0, // 0x00000008,
|
||||
Extended = 1, // 0x00000018,
|
||||
Explicit = 2, // 0x00000010,
|
||||
Auto = 3, // 0x00000000,
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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[] {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -3001,6 +3001,9 @@ private:
|
|||
|
||||
VOID HandleGCForExplicitLayout();
|
||||
|
||||
VOID HandleCStructLayout(
|
||||
MethodTable **);
|
||||
|
||||
VOID CheckForHFA(MethodTable ** pByValueClassCache);
|
||||
|
||||
VOID CheckForNativeHFA();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ namespace System.Runtime.InteropServices
|
|||
public enum LayoutKind
|
||||
{
|
||||
Sequential = 0,
|
||||
Extended = 1,
|
||||
Explicit = 2,
|
||||
Auto = 3,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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))]
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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...
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.IL">
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ExtendedLayoutTypes.il" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue