diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs index 98d5f338899a6e..366fca34842d7e 100644 --- a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs +++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs @@ -732,6 +732,8 @@ internal bool RequiresAlign8 { get { + if ((ExtendedFlags & (ushort)EETypeFlagsEx.RequiresAlign8Flag) != 0) + return true; return (RareFlags & EETypeRareFlags.RequiresAlign8Flag) != 0; } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/ThreadStatics.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/ThreadStatics.cs index 5134ed2884a91e..235a5fad23dd0e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/ThreadStatics.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/ThreadStatics.cs @@ -137,15 +137,7 @@ private static unsafe object AllocateThreadStaticStorageForType(TypeManagerHandl gcDesc = Internal.Runtime.Augments.RuntimeAugments.TypeLoaderCallbacks.GetThreadStaticGCDescForDynamicType(typeManager, typeTlsIndex); } - MethodTable *pMethodTable = (MethodTable*)gcDesc; -#if FEATURE_64BIT_ALIGNMENT - if (pMethodTable->RequiresAlign8) - { - return InternalCalls.RhpNewFastAlign8(pMethodTable); - } -#endif - - return RuntimeImports.RhNewObject(pMethodTable); + return RuntimeImports.RhNewObject((MethodTable*)gcDesc); } } } diff --git a/src/coreclr/tools/Common/Internal/Runtime/EETypeBuilderHelpers.cs b/src/coreclr/tools/Common/Internal/Runtime/EETypeBuilderHelpers.cs index 2f6d2c7f04d6fe..2e008b9a1debe4 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/EETypeBuilderHelpers.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/EETypeBuilderHelpers.cs @@ -128,6 +128,11 @@ mdType.Name is "WeakReference" or "WeakReference`1" && flagsEx |= (ushort)EETypeFlagsEx.IDynamicInterfaceCastableFlag; } + if (type.RequiresAlign8()) + { + flagsEx |= (ushort)EETypeFlagsEx.RequiresAlign8Flag; + } + return flagsEx; } diff --git a/src/coreclr/tools/Common/Internal/Runtime/MethodTable.Constants.cs b/src/coreclr/tools/Common/Internal/Runtime/MethodTable.Constants.cs index 4e0d70ab324715..cbac89e93257e7 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/MethodTable.Constants.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/MethodTable.Constants.cs @@ -84,6 +84,8 @@ internal enum EETypeFlagsEx : ushort /// This type implements IDynamicInterfaceCastable to allow dynamic resolution of interface casts. /// IDynamicInterfaceCastableFlag = 0x0008, + + RequiresAlign8Flag = 0x1000, } internal enum EETypeKind : uint diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs index 2907ba26b6cf27..8e57a848351d13 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs @@ -94,6 +94,10 @@ public static GCPointerMap FromStaticLayout(MetadataType type) builder.GetInnerBuilder(field.Offset.AsInt, fieldDefType.InstanceByteCount.AsInt); FromInstanceLayoutHelper(ref innerBuilder, fieldDefType); } + if (fieldDefType.RequiresAlign8()) + { + builder.RequiresAlign8(); + } } } @@ -122,6 +126,10 @@ private static void MapThreadStaticsForType(ref GCPointerMapBuilder builder, Met builder.GetInnerBuilder(field.Offset.AsInt + baseOffset, fieldDefType.InstanceByteCount.AsInt); FromInstanceLayoutHelper(ref innerBuilder, fieldDefType); } + if (fieldDefType.RequiresAlign8()) + { + builder.RequiresAlign8(); + } } } } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.cs index 0e2bacf49bfe80..972b16cbad8351 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.cs @@ -19,6 +19,8 @@ public partial struct GCPointerMap : IEquatable, IComparable /// Gets a value indicating whether this map is initialized. /// @@ -77,6 +79,8 @@ public bool IsAllGCPointers } } + public bool RequiresAlign8 => _requiresAlign8; + public bool this[int index] { get @@ -85,11 +89,12 @@ public bool this[int index] } } - public GCPointerMap(uint[] gcFlags, int numCells) + public GCPointerMap(uint[] gcFlags, int numCells, bool requiresAlign8) { Debug.Assert(numCells <= gcFlags.Length << 5); _gcFlags = gcFlags; _numCells = numCells; + _requiresAlign8 = requiresAlign8; } public BitEnumerator GetEnumerator() @@ -111,6 +116,9 @@ public bool Equals(GCPointerMap other) if (_gcFlags[i] != other._gcFlags[i]) return false; + if (_requiresAlign8 != other.RequiresAlign8) + return false; + return true; } @@ -141,6 +149,9 @@ public int CompareTo(GCPointerMap other) return (int)(_gcFlags[i] - other._gcFlags[i]); } + if (_requiresAlign8 != other.RequiresAlign8) + return _requiresAlign8 ? 1 : -1; + Debug.Assert(Equals(other)); return 0; } @@ -161,6 +172,8 @@ public struct GCPointerMapBuilder private int _delta; private int _limit; + private bool _requiresAlign8; + public GCPointerMapBuilder(int numBytes, int pointerSize) { // Align the size up. The size of the pointer map is used to infer the statics storage size that has @@ -183,6 +196,7 @@ public GCPointerMapBuilder(int numBytes, int pointerSize) _delta = 0; _limit = numBytes; + _requiresAlign8 = false; } public void MarkGCPointer(int offset) @@ -199,6 +213,11 @@ public void MarkGCPointer(int offset) _gcFlags[cellIndex >> 5] |= 1u << (cellIndex & 0x1F); } + public void RequiresAlign8() + { + _requiresAlign8 = true; + } + public GCPointerMapBuilder GetInnerBuilder(int offset, int size) { Debug.Assert(offset >= 0); @@ -219,7 +238,7 @@ public GCPointerMapBuilder GetInnerBuilder(int offset, int size) public GCPointerMap ToGCMap() { Debug.Assert(_delta == 0); - return new GCPointerMap(_gcFlags, (_limit + _pointerSize - 1) / _pointerSize); + return new GCPointerMap(_gcFlags, (_limit + _pointerSize - 1) / _pointerSize, _requiresAlign8); } public BitEnumerator GetEnumerator() diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs index 3d07c1c0068e8e..e1abc882a6ba15 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs @@ -1359,7 +1359,8 @@ private void ComputeRareFlags(NodeFactory factory) flags |= (uint)EETypeRareFlags.HasCctorFlag; } - if (_type.RequiresAlign8()) + // Types without component size use EETypeFlagsEx to store the RequiresAlign8 flag + if (!_type.IsArray && !_type.IsString && _type.RequiresAlign8()) { flags |= (uint)EETypeRareFlags.RequiresAlign8Flag; } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticEETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticEETypeNode.cs index 62df975327641d..59582a297e9e3a 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticEETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticEETypeNode.cs @@ -57,6 +57,8 @@ int ISymbolDefinitionNode.Offset public override bool IsShareable => true; + public bool RequiresAlign8 => _gcMap.RequiresAlign8; + protected override ObjectData GetDehydratableData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder dataBuilder = new ObjectDataBuilder(factory, relocsOnly); @@ -83,6 +85,13 @@ protected override ObjectData GetDehydratableData(NodeFactory factory, bool relo if (containsPointers) flags |= (uint)EETypeFlags.HasPointersFlag; + if (_gcMap.RequiresAlign8) + { + // Mark the method table as non-value type that requires 8-byte alignment + flags |= (uint)EETypeFlagsEx.RequiresAlign8Flag; + flags |= (uint)EETypeElementType.Class << (byte)EETypeFlags.ElementTypeShift; + } + dataBuilder.EmitUInt(flags); totalSize = Math.Max(totalSize, _target.PointerSize * 3); // minimum GC MethodTable size is 3 pointers