Skip to content

Commit da95abd

Browse files
Convert small atomic fallbacks to managed (#99011)
* Convert small atomic fallbacks to managed * Update Interlocked.cs * Fix Mono * Improve CompareExchange performance * Optimize for non-zero padding * Add static tests * Remove AsPointer Co-authored-by: Hamish Arblaster <hamarb123@gmail.com> * Fix build errors --------- Co-authored-by: Hamish Arblaster <hamarb123@gmail.com>
1 parent af6a9f3 commit da95abd

File tree

20 files changed

+390
-626
lines changed

20 files changed

+390
-626
lines changed

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

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -42,48 +42,6 @@ public static long Decrement(ref long location) =>
4242
#endregion
4343

4444
#region Exchange
45-
/// <summary>Sets a 8-bit unsigned integer to a specified value and returns the original value, as an atomic operation.</summary>
46-
/// <param name="location1">The variable to set to the specified value.</param>
47-
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
48-
/// <returns>The original value of <paramref name="location1"/>.</returns>
49-
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
50-
[Intrinsic]
51-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
52-
public static byte Exchange(ref byte location1, byte value)
53-
{
54-
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64
55-
return Exchange(ref location1, value); // Must expand intrinsic
56-
#else
57-
if (Unsafe.IsNullRef(ref location1))
58-
ThrowHelper.ThrowNullReferenceException();
59-
return Exchange8(ref location1, value);
60-
#endif
61-
}
62-
63-
[MethodImpl(MethodImplOptions.InternalCall)]
64-
private static extern byte Exchange8(ref byte location1, byte value);
65-
66-
/// <summary>Sets a 16-bit signed integer to a specified value and returns the original value, as an atomic operation.</summary>
67-
/// <param name="location1">The variable to set to the specified value.</param>
68-
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
69-
/// <returns>The original value of <paramref name="location1"/>.</returns>
70-
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
71-
[Intrinsic]
72-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
73-
public static short Exchange(ref short location1, short value)
74-
{
75-
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64
76-
return Exchange(ref location1, value); // Must expand intrinsic
77-
#else
78-
if (Unsafe.IsNullRef(ref location1))
79-
ThrowHelper.ThrowNullReferenceException();
80-
return Exchange16(ref location1, value);
81-
#endif
82-
}
83-
84-
[MethodImpl(MethodImplOptions.InternalCall)]
85-
private static extern short Exchange16(ref short location1, short value);
86-
8745
/// <summary>Sets a 32-bit signed integer to a specified value and returns the original value, as an atomic operation.</summary>
8846
/// <param name="location1">The variable to set to the specified value.</param>
8947
/// <param name="value">The value to which the <paramref name="location1"/> parameter is set.</param>
@@ -162,50 +120,6 @@ public static T Exchange<T>([NotNullIfNotNull(nameof(value))] ref T location1, T
162120
#endregion
163121

164122
#region CompareExchange
165-
/// <summary>Compares two 8-bit unsigned integers for equality and, if they are equal, replaces the first value.</summary>
166-
/// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
167-
/// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
168-
/// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
169-
/// <returns>The original value in <paramref name="location1"/>.</returns>
170-
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
171-
[Intrinsic]
172-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
173-
public static byte CompareExchange(ref byte location1, byte value, byte comparand)
174-
{
175-
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64
176-
return CompareExchange(ref location1, value, comparand); // Must expand intrinsic
177-
#else
178-
if (Unsafe.IsNullRef(ref location1))
179-
ThrowHelper.ThrowNullReferenceException();
180-
return CompareExchange8(ref location1, value, comparand);
181-
#endif
182-
}
183-
184-
[MethodImpl(MethodImplOptions.InternalCall)]
185-
private static extern byte CompareExchange8(ref byte location1, byte value, byte comparand);
186-
187-
/// <summary>Compares two 16-bit signed integers for equality and, if they are equal, replaces the first value.</summary>
188-
/// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
189-
/// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>
190-
/// <param name="comparand">The value that is compared to the value at <paramref name="location1"/>.</param>
191-
/// <returns>The original value in <paramref name="location1"/>.</returns>
192-
/// <exception cref="NullReferenceException">The address of <paramref name="location1"/> is a null pointer.</exception>
193-
[Intrinsic]
194-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
195-
public static short CompareExchange(ref short location1, short value, short comparand)
196-
{
197-
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64
198-
return CompareExchange(ref location1, value, comparand); // Must expand intrinsic
199-
#else
200-
if (Unsafe.IsNullRef(ref location1))
201-
ThrowHelper.ThrowNullReferenceException();
202-
return CompareExchange16(ref location1, value, comparand);
203-
#endif
204-
}
205-
206-
[MethodImpl(MethodImplOptions.InternalCall)]
207-
private static extern short CompareExchange16(ref short location1, short value, short comparand);
208-
209123
/// <summary>Compares two 32-bit signed integers for equality and, if they are equal, replaces the first value.</summary>
210124
/// <param name="location1">The destination, whose value is compared with <paramref name="comparand"/> and possibly replaced.</param>
211125
/// <param name="value">The value that replaces the destination value if the comparison results in equality.</param>

src/coreclr/inc/winwrap.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,4 @@ WszCreateProcess(
254254
LPPROCESS_INFORMATION lpProcessInformation
255255
);
256256

257-
#ifdef HOST_WINDOWS
258-
259-
//
260-
// Workaround for https://github.com/microsoft/WindowsAppSDK/issues/4074
261-
// Windows SDK is missing InterlockedCompareExchange8 definition.
262-
//
263-
#define InterlockedCompareExchange8 _InterlockedCompareExchange8
264-
265-
#endif // HOST_WINDOWS
266257
#endif // __WIN_WRAP_H__

src/coreclr/nativeaot/Runtime/EHHelpers.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,6 @@ EXTERN_C CODE_LOCATION RhpCheckedAssignRefEBPAVLocation;
329329
EXTERN_C CODE_LOCATION RhpCheckedLockCmpXchgAVLocation;
330330
EXTERN_C CODE_LOCATION RhpCheckedXchgAVLocation;
331331
#if !defined(HOST_AMD64) && !defined(HOST_ARM64)
332-
EXTERN_C CODE_LOCATION RhpLockCmpXchg8AVLocation;
333-
EXTERN_C CODE_LOCATION RhpLockCmpXchg16AVLocation;
334332
EXTERN_C CODE_LOCATION RhpLockCmpXchg32AVLocation;
335333
EXTERN_C CODE_LOCATION RhpLockCmpXchg64AVLocation;
336334
#endif
@@ -372,8 +370,6 @@ static bool InWriteBarrierHelper(uintptr_t faultingIP)
372370
(uintptr_t)&RhpCheckedXchgAVLocation,
373371
#if !defined(HOST_AMD64) && !defined(HOST_ARM64)
374372
#if !defined(HOST_X86)
375-
(uintptr_t)&RhpLockCmpXchg8AVLocation,
376-
(uintptr_t)&RhpLockCmpXchg16AVLocation,
377373
(uintptr_t)&RhpLockCmpXchg32AVLocation,
378374
#endif
379375
(uintptr_t)&RhpLockCmpXchg64AVLocation,

src/coreclr/nativeaot/Runtime/arm/Interlocked.S

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,6 @@
77
#include <AsmOffsets.inc> // generated by the build from AsmOffsets.cpp
88
#include <unixasmmacros.inc>
99

10-
// WARNING: Code in EHHelpers.cpp makes assumptions about this helper, in particular:
11-
// - Function "InWriteBarrierHelper" assumes an AV due to passed in null pointer will happen at RhpLockCmpXchg8AVLocation
12-
// - Function "UnwindSimpleHelperToCaller" assumes no registers were pushed and LR contains the return address
13-
// r0 = destination address
14-
// r1 = value
15-
// r2 = comparand
16-
LEAF_ENTRY RhpLockCmpXchg8, _TEXT
17-
dmb
18-
GLOBAL_LABEL RhpLockCmpXchg8AVLocation
19-
LOCAL_LABEL(CmpXchg8Retry):
20-
ldrexb r3, [r0]
21-
cmp r2, r3
22-
bne LOCAL_LABEL(CmpXchg8Exit)
23-
strexb r12, r1, [r0]
24-
cmp r12, #0
25-
bne LOCAL_LABEL(CmpXchg8Retry)
26-
LOCAL_LABEL(CmpXchg8Exit):
27-
mov r0, r3
28-
dmb
29-
bx lr
30-
LEAF_END RhpLockCmpXchg8, _TEXT
31-
32-
// WARNING: Code in EHHelpers.cpp makes assumptions about this helper, in particular:
33-
// - Function "InWriteBarrierHelper" assumes an AV due to passed in null pointer will happen at RhpLockCmpXchg16AVLocation
34-
// - Function "UnwindSimpleHelperToCaller" assumes no registers were pushed and LR contains the return address
35-
// r0 = destination address
36-
// r1 = value
37-
// r2 = comparand
38-
LEAF_ENTRY RhpLockCmpXchg16, _TEXT
39-
uxth r2, r2
40-
dmb
41-
GLOBAL_LABEL RhpLockCmpXchg16AVLocation
42-
LOCAL_LABEL(CmpXchg16Retry):
43-
ldrexh r3, [r0]
44-
cmp r2, r3
45-
bne LOCAL_LABEL(CmpXchg16Exit)
46-
strexh r12, r1, [r0]
47-
cmp r12, #0
48-
bne LOCAL_LABEL(CmpXchg16Retry)
49-
LOCAL_LABEL(CmpXchg16Exit):
50-
sxth r0, r3
51-
dmb
52-
bx lr
53-
LEAF_END RhpLockCmpXchg16, _TEXT
54-
5510
// WARNING: Code in EHHelpers.cpp makes assumptions about this helper, in particular:
5611
// - Function "InWriteBarrierHelper" assumes an AV due to passed in null pointer will happen at RhpLockCmpXchg32AVLocation
5712
// - Function "UnwindSimpleHelperToCaller" assumes no registers were pushed and LR contains the return address

src/coreclr/nativeaot/Runtime/portable.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -390,20 +390,6 @@ FCIMPL2(Object *, RhpCheckedXchg, Object ** location, Object * value)
390390
}
391391
FCIMPLEND
392392

393-
FCIMPL3(uint8_t, RhpLockCmpXchg8, uint8_t * location, uint8_t value, uint8_t comparand)
394-
{
395-
ASSERT_UNCONDITIONALLY("NYI");
396-
return 0;
397-
}
398-
FCIMPLEND
399-
400-
FCIMPL3(int16_t, RhpLockCmpXchg16, int16_t * location, int16_t value, int16_t comparand)
401-
{
402-
ASSERT_UNCONDITIONALLY("NYI");
403-
return 0;
404-
}
405-
FCIMPLEND
406-
407393
FCIMPL3(int32_t, RhpLockCmpXchg32, int32_t * location, int32_t value, int32_t comparand)
408394
{
409395
// @TODO: USE_PORTABLE_HELPERS - Null check

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -645,14 +645,6 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe
645645
//
646646
// Interlocked helpers
647647
//
648-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
649-
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg8")]
650-
internal static extern byte InterlockedCompareExchange(ref byte location1, byte value, byte comparand);
651-
652-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
653-
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg16")]
654-
internal static extern short InterlockedCompareExchange(ref short location1, short value, short comparand);
655-
656648
[MethodImplAttribute(MethodImplOptions.InternalCall)]
657649
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg32")]
658650
internal static extern int InterlockedCompareExchange(ref int location1, int value, int comparand);

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

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,6 @@ public static partial class Interlocked
1111
{
1212
#region CompareExchange
1313

14-
[Intrinsic]
15-
public static byte CompareExchange(ref byte location1, byte value, byte comparand)
16-
{
17-
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64
18-
return CompareExchange(ref location1, value, comparand);
19-
#else
20-
return RuntimeImports.InterlockedCompareExchange(ref location1, value, comparand);
21-
#endif
22-
}
23-
24-
[Intrinsic]
25-
public static short CompareExchange(ref short location1, short value, short comparand)
26-
{
27-
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64
28-
return CompareExchange(ref location1, value, comparand);
29-
#else
30-
return RuntimeImports.InterlockedCompareExchange(ref location1, value, comparand);
31-
#endif
32-
}
33-
3414
[Intrinsic]
3515
public static int CompareExchange(ref int location1, int value, int comparand)
3616
{
@@ -70,40 +50,6 @@ public static T CompareExchange<T>(ref T location1, T value, T comparand) where
7050

7151
#region Exchange
7252

73-
[Intrinsic]
74-
public static byte Exchange(ref byte location1, byte value)
75-
{
76-
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64
77-
return Exchange(ref location1, value);
78-
#else
79-
byte oldValue;
80-
81-
do
82-
{
83-
oldValue = location1;
84-
} while (CompareExchange(ref location1, value, oldValue) != oldValue);
85-
86-
return oldValue;
87-
#endif
88-
}
89-
90-
[Intrinsic]
91-
public static short Exchange(ref short location1, short value)
92-
{
93-
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64
94-
return Exchange(ref location1, value);
95-
#else
96-
short oldValue;
97-
98-
do
99-
{
100-
oldValue = location1;
101-
} while (CompareExchange(ref location1, value, oldValue) != oldValue);
102-
103-
return oldValue;
104-
#endif
105-
}
106-
10753
[Intrinsic]
10854
public static int Exchange(ref int location1, int value)
10955
{

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,6 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe
9090
//
9191
// Interlocked helpers
9292
//
93-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
94-
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg8")]
95-
internal static extern byte InterlockedCompareExchange(ref byte location1, byte value, byte comparand);
96-
97-
[MethodImplAttribute(MethodImplOptions.InternalCall)]
98-
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg16")]
99-
internal static extern short InterlockedCompareExchange(ref short location1, short value, short comparand);
100-
10193
[MethodImplAttribute(MethodImplOptions.InternalCall)]
10294
[RuntimeImport(RuntimeLibrary, "RhpLockCmpXchg32")]
10395
internal static extern int InterlockedCompareExchange(ref int location1, int value, int comparand);

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

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,6 @@ public static IntPtr CompareExchange(ref IntPtr location1, IntPtr value, IntPtr
1818
#endif
1919
}
2020

21-
[Intrinsic]
22-
public static byte CompareExchange(ref byte location1, byte value, byte comparand)
23-
{
24-
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64
25-
return CompareExchange(ref location1, value, comparand);
26-
#else
27-
return RuntimeImports.InterlockedCompareExchange(ref location1, value, comparand);
28-
#endif
29-
}
30-
31-
[Intrinsic]
32-
public static short CompareExchange(ref short location1, short value, short comparand)
33-
{
34-
#if TARGET_X86 || TARGET_AMD64 || TARGET_ARM64
35-
return CompareExchange(ref location1, value, comparand);
36-
#else
37-
return RuntimeImports.InterlockedCompareExchange(ref location1, value, comparand);
38-
#endif
39-
}
40-
4121
[Intrinsic]
4222
public static int CompareExchange(ref int location1, int value, int comparand)
4323
{

src/coreclr/pal/inc/pal.h

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3636,20 +3636,6 @@ Return Values
36363636
The function returns the initial value pointed to by Target.
36373637
36383638
--*/
3639-
Define_InterlockMethod(
3640-
CHAR,
3641-
InterlockedExchange8(IN OUT CHAR volatile *Target, CHAR Value),
3642-
InterlockedExchange8(Target, Value),
3643-
__atomic_exchange_n(Target, Value, __ATOMIC_ACQ_REL)
3644-
)
3645-
3646-
Define_InterlockMethod(
3647-
SHORT,
3648-
InterlockedExchange16(IN OUT SHORT volatile *Target, SHORT Value),
3649-
InterlockedExchange16(Target, Value),
3650-
__atomic_exchange_n(Target, Value, __ATOMIC_ACQ_REL)
3651-
)
3652-
36533639
Define_InterlockMethod(
36543640
LONG,
36553641
InterlockedExchange(IN OUT LONG volatile *Target, LONG Value),
@@ -3708,26 +3694,6 @@ Return Values
37083694
The return value is the initial value of the destination.
37093695
37103696
--*/
3711-
Define_InterlockMethod(
3712-
CHAR,
3713-
InterlockedCompareExchange8(IN OUT CHAR volatile *Destination, IN CHAR Exchange, IN CHAR Comperand),
3714-
InterlockedCompareExchange8(Destination, Exchange, Comperand),
3715-
__sync_val_compare_and_swap(
3716-
Destination, /* The pointer to a variable whose value is to be compared with. */
3717-
Comperand, /* The value to be compared */
3718-
Exchange /* The value to be stored */)
3719-
)
3720-
3721-
Define_InterlockMethod(
3722-
SHORT,
3723-
InterlockedCompareExchange16(IN OUT SHORT volatile *Destination, IN SHORT Exchange, IN SHORT Comperand),
3724-
InterlockedCompareExchange16(Destination, Exchange, Comperand),
3725-
__sync_val_compare_and_swap(
3726-
Destination, /* The pointer to a variable whose value is to be compared with. */
3727-
Comperand, /* The value to be compared */
3728-
Exchange /* The value to be stored */)
3729-
)
3730-
37313697
Define_InterlockMethod(
37323698
LONG,
37333699
InterlockedCompareExchange(IN OUT LONG volatile *Destination, IN LONG Exchange, IN LONG Comperand),

0 commit comments

Comments
 (0)