@@ -18,6 +18,7 @@ private static readonly HashSet<Type> SupportedTypes
18
18
. Where ( field => ! field . IsStatic ) // exclude this HashSet itself
19
19
. Select ( field => field . FieldType ) ) ;
20
20
21
+ #pragma warning disable IDE0052 // Remove unread private members
21
22
private volatile byte byteHolder ;
22
23
private volatile sbyte sbyteHolder ;
23
24
private volatile short shortHolder ;
@@ -30,10 +31,10 @@ private static readonly HashSet<Type> SupportedTypes
30
31
private double doubleHolder ;
31
32
private long longHolder ;
32
33
private ulong ulongHolder ;
33
- private string stringHolder ;
34
- private object objectHolder ;
35
- private IntPtr ptrHolder ;
36
- private UIntPtr uptrHolder ;
34
+ private volatile object objectHolder ;
35
+ private volatile IntPtr ptrHolder ;
36
+ private volatile UIntPtr uptrHolder ;
37
+ #pragma warning restore IDE0052 // Remove unread private members
37
38
38
39
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
39
40
[ PublicAPI ]
@@ -84,11 +85,11 @@ private static readonly HashSet<Type> SupportedTypes
84
85
85
86
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
86
87
[ PublicAPI ]
87
- public void Consume ( IntPtr intPtrValue ) => Volatile . Write ( ref ptrHolder , intPtrValue ) ;
88
+ public void Consume ( IntPtr intPtrValue ) => ptrHolder = intPtrValue ;
88
89
89
90
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
90
91
[ PublicAPI ]
91
- public void Consume ( UIntPtr uintPtrValue ) => Volatile . Write ( ref uptrHolder , uintPtrValue ) ;
92
+ public void Consume ( UIntPtr uintPtrValue ) => uptrHolder = uintPtrValue ;
92
93
93
94
[ CLSCompliant ( false ) ]
94
95
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -97,22 +98,28 @@ private static readonly HashSet<Type> SupportedTypes
97
98
98
99
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
99
100
[ PublicAPI ]
100
- public void Consume ( string stringValue ) => Volatile . Write ( ref stringHolder , stringValue ) ;
101
+ public void Consume ( string stringValue ) => Consume ( ( object ) stringValue ) ;
101
102
102
103
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
103
104
[ PublicAPI ]
104
- public void Consume ( object objectValue ) => Volatile . Write ( ref objectHolder , objectValue ) ;
105
+ public void Consume ( object objectValue )
106
+ {
107
+ // Write to volatile field to prevent dead code elimination and out-of-order execution.
108
+ objectHolder = objectValue ;
109
+ // Overwrite field to null so we aren't holding onto references to affect GC behavior. (#1942)
110
+ objectHolder = null ;
111
+ }
105
112
106
113
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
107
114
[ PublicAPI ]
108
115
public void Consume < T > ( T objectValue ) where T : class // class constraint prevents from boxing structs
109
- => Volatile . Write ( ref objectHolder , objectValue ) ;
116
+ => Consume ( ( object ) objectValue ) ;
110
117
111
118
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
112
- public unsafe void Consume < T > ( T * ptrValue ) where T : unmanaged => Volatile . Write ( ref ptrHolder , ( IntPtr ) ptrValue ) ;
119
+ public unsafe void Consume < T > ( T * ptrValue ) where T : unmanaged => ptrHolder = ( IntPtr ) ptrValue ;
113
120
114
121
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
115
- public unsafe void Consume ( void * ptrValue ) => Volatile . Write ( ref ptrHolder , ( IntPtr ) ptrValue ) ;
122
+ public unsafe void Consume ( void * ptrValue ) => ptrHolder = ( IntPtr ) ptrValue ;
116
123
117
124
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
118
125
public void Consume < T > ( in T value )
@@ -141,15 +148,12 @@ public void Consume<T>(in T value)
141
148
Volatile . Write ( ref longHolder , ( long ) ( object ) value ) ;
142
149
else if ( typeof ( T ) == typeof ( ulong ) )
143
150
Volatile . Write ( ref ulongHolder , ( ulong ) ( object ) value ) ;
144
- else if ( default ( T ) == null )
145
- objectHolder = ( object ) value ;
151
+ else if ( default ( T ) == null && ! typeof ( T ) . IsValueType )
152
+ Consume ( ( object ) value ) ;
146
153
else
147
- ValueTypesConsumer ( value ) ; // non-primitive value types
154
+ DeadCodeEliminationHelper . KeepAliveWithoutBoxingReadonly ( value ) ; // non-primitive and nullable value types
148
155
}
149
156
150
- [ MethodImpl ( MethodImplOptions . NoInlining ) ]
151
- private void ValueTypesConsumer < T > ( in T _ ) { }
152
-
153
157
internal static bool IsConsumable ( Type type )
154
158
=> SupportedTypes . Contains ( type ) || type . GetTypeInfo ( ) . IsClass || type . GetTypeInfo ( ) . IsInterface ;
155
159
0 commit comments