@@ -30,8 +30,9 @@ private static readonly HashSet<Type> SupportedTypes
30
30
private double doubleHolder ;
31
31
private long longHolder ;
32
32
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 ;
35
36
36
37
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
37
38
[ PublicAPI ]
@@ -82,11 +83,11 @@ private static readonly HashSet<Type> SupportedTypes
82
83
83
84
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
84
85
[ PublicAPI ]
85
- public void Consume ( IntPtr intPtrValue ) => Volatile . Write ( ref ptrHolder , intPtrValue ) ;
86
+ public void Consume ( IntPtr intPtrValue ) => ptrHolder = intPtrValue ;
86
87
87
88
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
88
89
[ PublicAPI ]
89
- public void Consume ( UIntPtr uintPtrValue ) => Volatile . Write ( ref uptrHolder , uintPtrValue ) ;
90
+ public void Consume ( UIntPtr uintPtrValue ) => uptrHolder = uintPtrValue ;
90
91
91
92
[ CLSCompliant ( false ) ]
92
93
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -95,22 +96,35 @@ private static readonly HashSet<Type> SupportedTypes
95
96
96
97
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
97
98
[ 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
+ }
99
106
100
107
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
101
108
[ PublicAPI ]
102
- public void Consume ( object objectValue ) => DeadCodeEliminationHelper . KeepAliveWithoutBoxing ( objectValue ) ;
109
+ public void Consume ( object objectValue )
110
+ {
111
+ objectHolder = objectValue ;
112
+ objectHolder = null ;
113
+ }
103
114
104
115
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
105
116
[ PublicAPI ]
106
117
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
+ }
108
122
109
123
[ 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 ;
111
125
112
126
[ 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 ;
114
128
115
129
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
116
130
public void Consume < T > ( in T value )
@@ -139,6 +153,11 @@ public void Consume<T>(in T value)
139
153
Volatile . Write ( ref longHolder , ( long ) ( object ) value ) ;
140
154
else if ( typeof ( T ) == typeof ( ulong ) )
141
155
Volatile . Write ( ref ulongHolder , ( ulong ) ( object ) value ) ;
156
+ else if ( default ( T ) == null && ! typeof ( T ) . IsValueType )
157
+ {
158
+ objectHolder = value ;
159
+ objectHolder = null ;
160
+ }
142
161
else
143
162
DeadCodeEliminationHelper . KeepAliveWithoutBoxingReadonly ( value ) ; // non-primitive and nullable value types
144
163
}
0 commit comments