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 235a5fad23dd..934f36a9943b 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,13 @@ private static unsafe object AllocateThreadStaticStorageForType(TypeManagerHandl gcDesc = Internal.Runtime.Augments.RuntimeAugments.TypeLoaderCallbacks.GetThreadStaticGCDescForDynamicType(typeManager, typeTlsIndex); } +#if TARGET_WASM + // TODO-LLVM: Remove when there is an upstream fix. See https://github.com/dotnet/runtimelab/issues/2606 and https://github.com/dotnet/runtime/issues/103234 + // This is a fix for aligning to 8, thread static fields that should be aligned 8, we just conservatively align everything to 8. + return InternalCalls.RhpNewFastAlign8((MethodTable*)gcDesc); +#else return RuntimeImports.RhNewObject((MethodTable*)gcDesc); +#endif } } } diff --git a/src/tests/nativeaot/SmokeTests/HelloWasm/HelloWasm.cs b/src/tests/nativeaot/SmokeTests/HelloWasm/HelloWasm.cs index b7e536a89506..62f5c8444420 100644 --- a/src/tests/nativeaot/SmokeTests/HelloWasm/HelloWasm.cs +++ b/src/tests/nativeaot/SmokeTests/HelloWasm/HelloWasm.cs @@ -429,6 +429,8 @@ private static unsafe int Main(string[] args) LSSATests.Run(); + TestThreadStaticAlignment(); + if (OperatingSystem.IsBrowser()) { EventLoopTestClass.TestEventLoopIntegration(); @@ -4251,6 +4253,49 @@ static void TestGenStructContains() EndTest(contains); } + [InlineArray(3)] + internal struct ReturnArea + { + private ulong buffer; + + internal unsafe nint AddressOfReturnArea() + { + return (nint)Unsafe.AsPointer(ref buffer); + } + } + + internal class ThreadStaticAlignCheck1 + { + [ThreadStatic] + [FixedAddressValueType] + internal static ReturnArea returnArea = default; + } + + internal class Padder + { + private object o1; + } + + internal class ThreadStaticAlignCheck2 + { + [ThreadStatic] + [FixedAddressValueType] + internal static ReturnArea returnArea = default; + } + + static void TestThreadStaticAlignment() + { + StartTest("Test ThreadStatic Alignment"); + + // 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(); + + EndTest((((nint)ts1Addr) % 8 == 0) && (((nint)ts2Addr) % 8 == 0)); + } + static ushort ReadUInt16() { // something with MSB set