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 235a5fad23dd0..5134ed2884a91 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,7 +137,15 @@ private static unsafe object AllocateThreadStaticStorageForType(TypeManagerHandl gcDesc = Internal.Runtime.Augments.RuntimeAugments.TypeLoaderCallbacks.GetThreadStaticGCDescForDynamicType(typeManager, typeTlsIndex); } - return RuntimeImports.RhNewObject((MethodTable*)gcDesc); + MethodTable *pMethodTable = (MethodTable*)gcDesc; +#if FEATURE_64BIT_ALIGNMENT + if (pMethodTable->RequiresAlign8) + { + return InternalCalls.RhpNewFastAlign8(pMethodTable); + } +#endif + + return RuntimeImports.RhNewObject(pMethodTable); } } } diff --git a/src/tests/nativeaot/SmokeTests/UnitTests/BasicThreading.cs b/src/tests/nativeaot/SmokeTests/UnitTests/BasicThreading.cs index 0b62338d53628..d8c9a9eb62a50 100644 --- a/src/tests/nativeaot/SmokeTests/UnitTests/BasicThreading.cs +++ b/src/tests/nativeaot/SmokeTests/UnitTests/BasicThreading.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -18,6 +19,9 @@ internal static int Run() ThreadStaticsTestWithTasks.Run(); + if (ThreadStaticAlignmentTest.Run() != Pass) + return Fail; + if (ThreadTest.Run() != Pass) return Fail; @@ -187,6 +191,59 @@ public static void Run() } } +class ThreadStaticAlignmentTest +{ + public static int Run() + { + // Check for 8-byte alignment requirement + if (RuntimeInformation.ProcessArchitecture is Architecture.Arm or Architecture.Wasm) + { + // Assume that these are allocated sequentially, use a padding object of size 12 (mod 8 is not 0) + // to move the alignment of the second AddressOfReturnArea in case the first is coincidentally aligned 8. + var ts1Addr = ThreadStaticAlignCheck1.returnArea.AddressOfReturnArea(); + var p = new Padder(); + var ts2Addr = ThreadStaticAlignCheck2.returnArea.AddressOfReturnArea(); + + if (((nint)ts1Addr) % 8 != 0) + return BasicThreading.Fail; + if (((nint)ts2Addr) % 8 != 0) + return BasicThreading.Fail; + } + + return BasicThreading.Pass; + } + + [InlineArray(3)] + private struct ReturnArea + { + private ulong buffer; + + internal unsafe nint AddressOfReturnArea() + { + return (nint)Unsafe.AsPointer(ref buffer); + } + } + + private class ThreadStaticAlignCheck1 + { + [ThreadStatic] + [FixedAddressValueType] + internal static ReturnArea returnArea = default; + } + + private class Padder + { + private object o1; + } + + private class ThreadStaticAlignCheck2 + { + [ThreadStatic] + [FixedAddressValueType] + internal static ReturnArea returnArea = default; + } +} + class ThreadTest { private static readonly List s_startedThreads = new List();