Skip to content

Commit 02bb8c3

Browse files
github-actions[bot]VSadovjkotasjeffschwMSFT
authored
[release/9.0] [NativeAOT] Introduce pointer-based CompareExchange intrinsic and use operating with syncblock bits. (#106727)
* introduce CompareExchange(int* location1, int value, int comparand) * Apply suggestions from code review Co-authored-by: Jan Kotas <[email protected]> * fix arm32 build --------- Co-authored-by: vsadov <[email protected]> Co-authored-by: Vladimir Sadov <[email protected]> Co-authored-by: Jan Kotas <[email protected]> Co-authored-by: Jeff Schwartz <[email protected]>
1 parent a7154bd commit 02bb8c3

File tree

4 files changed

+33
-6
lines changed

4 files changed

+33
-6
lines changed

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,10 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe
649649
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg32")]
650650
internal static extern int InterlockedCompareExchange(ref int location1, int value, int comparand);
651651

652+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
653+
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg32")]
654+
internal static extern unsafe int InterlockedCompareExchange(int* location1, int value, int comparand);
655+
652656
[MethodImplAttribute(MethodImplOptions.InternalCall)]
653657
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg64")]
654658
internal static extern long InterlockedCompareExchange(ref long location1, long value, long comparand);

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Interlocked.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Diagnostics.CodeAnalysis;
56
using System.Runtime;
67
using System.Runtime.CompilerServices;
@@ -23,6 +24,24 @@ public static int CompareExchange(ref int location1, int value, int comparand)
2324
#endif
2425
}
2526

27+
// This is used internally by NativeAOT runtime in cases where having a managed
28+
// ref to the location is unsafe (Ex: it is the syncblock of a pinned object).
29+
// The intrinsic expansion for this overload is exactly the same as for the `ref int`
30+
// variant and will go on the same path since expansion is triggered by the name and
31+
// return type of the method.
32+
// The important part is avoiding `ref *location` in the unexpanded scenario, like
33+
// in a case when compiling the Debug flavor of the app.
34+
[Intrinsic]
35+
internal static unsafe int CompareExchange(int* location1, int value, int comparand)
36+
{
37+
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64 || TARGET_RISCV64
38+
return CompareExchange(location1, value, comparand); // Must expand intrinsic
39+
#else
40+
Debug.Assert(location1 != null);
41+
return RuntimeImports.InterlockedCompareExchange(location1, value, comparand);
42+
#endif
43+
}
44+
2645
[Intrinsic]
2746
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2847
public static long CompareExchange(ref long location1, long value, long comparand)

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/ObjectHeader.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ private static unsafe int AssignHashCode(object o, int* pHeader)
152152
// there is nothing - try set hashcode inline
153153
Debug.Assert((oldBits & BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX) == 0);
154154
int newBits = BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_IS_HASHCODE | oldBits | newHash;
155-
if (Interlocked.CompareExchange(ref *pHeader, newBits, oldBits) == oldBits)
155+
if (Interlocked.CompareExchange(pHeader, newBits, oldBits) == oldBits)
156156
{
157157
return newHash;
158158
}
@@ -247,7 +247,7 @@ public static unsafe void SetSyncEntryIndex(int* pHeader, int syncIndex)
247247
newBits = oldBits & ~(BIT_SBLK_IS_HASHCODE | MASK_HASHCODE_INDEX);
248248
newBits |= syncIndex | BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX;
249249
}
250-
while (Interlocked.CompareExchange(ref *pHeader, newBits, oldBits) != oldBits);
250+
while (Interlocked.CompareExchange(pHeader, newBits, oldBits) != oldBits);
251251
}
252252

253253
//
@@ -312,7 +312,7 @@ public static unsafe int TryAcquire(object obj, int currentThreadID, bool oneSho
312312
// N.B. hashcode, thread ID and sync index are never 0, and hashcode is largest of all
313313
if ((oldBits & MASK_HASHCODE_INDEX) == 0)
314314
{
315-
if (Interlocked.CompareExchange(ref *pHeader, oldBits | currentThreadID, oldBits) == oldBits)
315+
if (Interlocked.CompareExchange(pHeader, oldBits | currentThreadID, oldBits) == oldBits)
316316
{
317317
return -1;
318318
}
@@ -369,7 +369,7 @@ private static unsafe int TryAcquireUncommon(object obj, int currentThreadID, bo
369369
if ((oldBits & MASK_HASHCODE_INDEX) == 0)
370370
{
371371
int newBits = oldBits | currentThreadID;
372-
if (Interlocked.CompareExchange(ref *pHeader, newBits, oldBits) == oldBits)
372+
if (Interlocked.CompareExchange(pHeader, newBits, oldBits) == oldBits)
373373
{
374374
return -1;
375375
}
@@ -398,7 +398,7 @@ private static unsafe int TryAcquireUncommon(object obj, int currentThreadID, bo
398398
int newBits = oldBits + SBLK_LOCK_RECLEVEL_INC;
399399
if ((newBits & SBLK_MASK_LOCK_RECLEVEL) != 0)
400400
{
401-
if (Interlocked.CompareExchange(ref *pHeader, newBits, oldBits) == oldBits)
401+
if (Interlocked.CompareExchange(pHeader, newBits, oldBits) == oldBits)
402402
{
403403
return -1;
404404
}
@@ -458,7 +458,7 @@ public static unsafe void Release(object obj)
458458
oldBits - SBLK_LOCK_RECLEVEL_INC :
459459
oldBits & ~SBLK_MASK_LOCK_THREADID;
460460

461-
if (Interlocked.CompareExchange(ref *pHeader, newBits, oldBits) == oldBits)
461+
if (Interlocked.CompareExchange(pHeader, newBits, oldBits) == oldBits)
462462
{
463463
return;
464464
}

src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/RuntimeImports.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe
9494
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg32")]
9595
internal static extern int InterlockedCompareExchange(ref int location1, int value, int comparand);
9696

97+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
98+
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg32")]
99+
internal static extern unsafe int InterlockedCompareExchange(int* location1, int value, int comparand);
100+
97101
[MethodImplAttribute(MethodImplOptions.InternalCall)]
98102
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg64")]
99103
internal static extern long InterlockedCompareExchange(ref long location1, long value, long comparand);

0 commit comments

Comments
 (0)