From 29858396e5c6dc49df434d6d80d40032b451beca Mon Sep 17 00:00:00 2001 From: yowl00 Date: Mon, 10 Jun 2024 14:13:44 +0100 Subject: [PATCH 1/2] workaround to align thread statics to 8 byte boundary --- .../src/Internal/Runtime/ThreadStatics.cs | 6 ++++++ 1 file changed, 6 insertions(+) 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..c00d4db77d6e 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 + // 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 } } } From 9c15021b7744608469caf5de9b3627402950383e Mon Sep 17 00:00:00 2001 From: yowl00 Date: Wed, 12 Jun 2024 12:24:41 +0100 Subject: [PATCH 2/2] add test for thread static alignment --- .../src/Internal/Runtime/ThreadStatics.cs | 2 +- .../SmokeTests/HelloWasm/HelloWasm.cs | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) 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 c00d4db77d6e..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 @@ -138,7 +138,7 @@ private static unsafe object AllocateThreadStaticStorageForType(TypeManagerHandl } #if TARGET_WASM - // TODO-LLVM: Remove when there is an upstream fix. See https://github.com/dotnet/runtimelab/issues/2606 + // 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 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