Skip to content

Commit 9cb5b48

Browse files
committed
Overwrite field to null instead of calling DeadCodeEliminationHelper.KeepAliveWithoutBoxing.
1 parent df10294 commit 9cb5b48

File tree

1 file changed

+28
-9
lines changed

1 file changed

+28
-9
lines changed

src/BenchmarkDotNet/Engines/Consumer.cs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ private static readonly HashSet<Type> SupportedTypes
3030
private double doubleHolder;
3131
private long longHolder;
3232
private ulong ulongHolder;
33-
private IntPtr ptrHolder;
34-
private UIntPtr uptrHolder;
33+
private volatile object objectHolder;
34+
private volatile IntPtr ptrHolder;
35+
private volatile UIntPtr uptrHolder;
3536

3637
[MethodImpl(MethodImplOptions.AggressiveInlining)]
3738
[PublicAPI]
@@ -82,11 +83,11 @@ private static readonly HashSet<Type> SupportedTypes
8283

8384
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8485
[PublicAPI]
85-
public void Consume(IntPtr intPtrValue) => Volatile.Write(ref ptrHolder, intPtrValue);
86+
public void Consume(IntPtr intPtrValue) => ptrHolder = intPtrValue;
8687

8788
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8889
[PublicAPI]
89-
public void Consume(UIntPtr uintPtrValue) => Volatile.Write(ref uptrHolder, uintPtrValue);
90+
public void Consume(UIntPtr uintPtrValue) => uptrHolder = uintPtrValue;
9091

9192
[CLSCompliant(false)]
9293
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -95,22 +96,35 @@ private static readonly HashSet<Type> SupportedTypes
9596

9697
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9798
[PublicAPI]
98-
public void Consume(string stringValue) => DeadCodeEliminationHelper.KeepAliveWithoutBoxing(stringValue);
99+
public void Consume(string stringValue)
100+
{
101+
// Write to volatile field to prevent dead code elimination and out-of-order execution.
102+
objectHolder = stringValue;
103+
// Overwrite field to null so we aren't holding onto references to affect GC behavior. (#1942)
104+
objectHolder = null;
105+
}
99106

100107
[MethodImpl(MethodImplOptions.AggressiveInlining)]
101108
[PublicAPI]
102-
public void Consume(object objectValue) => DeadCodeEliminationHelper.KeepAliveWithoutBoxing(objectValue);
109+
public void Consume(object objectValue)
110+
{
111+
objectHolder = objectValue;
112+
objectHolder = null;
113+
}
103114

104115
[MethodImpl(MethodImplOptions.AggressiveInlining)]
105116
[PublicAPI]
106117
public void Consume<T>(T objectValue) where T : class // class constraint prevents from boxing structs
107-
=> DeadCodeEliminationHelper.KeepAliveWithoutBoxing(objectValue);
118+
{
119+
objectHolder = objectValue;
120+
objectHolder = null;
121+
}
108122

109123
[MethodImpl(MethodImplOptions.AggressiveInlining)]
110-
public unsafe void Consume<T>(T* ptrValue) where T: unmanaged => Volatile.Write(ref ptrHolder, (IntPtr)ptrValue);
124+
public unsafe void Consume<T>(T* ptrValue) where T : unmanaged => ptrHolder = (IntPtr) ptrValue;
111125

112126
[MethodImpl(MethodImplOptions.AggressiveInlining)]
113-
public unsafe void Consume(void* ptrValue) => Volatile.Write(ref ptrHolder, (IntPtr)ptrValue);
127+
public unsafe void Consume(void* ptrValue) => ptrHolder = (IntPtr) ptrValue;
114128

115129
[MethodImpl(MethodImplOptions.AggressiveInlining)]
116130
public void Consume<T>(in T value)
@@ -139,6 +153,11 @@ public void Consume<T>(in T value)
139153
Volatile.Write(ref longHolder, (long)(object)value);
140154
else if (typeof(T) == typeof(ulong))
141155
Volatile.Write(ref ulongHolder, (ulong)(object)value);
156+
else if (default(T) == null && !typeof(T).IsValueType)
157+
{
158+
objectHolder = value;
159+
objectHolder = null;
160+
}
142161
else
143162
DeadCodeEliminationHelper.KeepAliveWithoutBoxingReadonly(value); // non-primitive and nullable value types
144163
}

0 commit comments

Comments
 (0)