[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / gcstress.h
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5
6 // 
7 // #Overview
8 // 
9 // This file provides convenient wrappers for the GC stress functionality.
10 // 
11 // Exposed APIs:
12 //  GCStressPolicy::InhibitHolder
13 //  GCStressPolicy::GlobalEnable()
14 //  GCStressPolicy::GlobalDisable()
15 //  GCStressPolicy::IsEnabled()
16 // 
17 //  GCStress<> template classes with its IsEnabled() & MaybeTrigger members.
18 // 
19 //  Use GCStress<> to abstract away the GC stress related decissions. The 
20 //  template definitions will resolve to nothing when STRESS_HEAP is not 
21 //  defined, and will inline the function body at the call site otherwise.
22 // 
23 // Examples:
24 //  GCStress<cfg_any>::IsEnabled()
25 //  GCStress<cfg_any, EeconfigFastGcSPolicy, CoopGcModePolicy>::MaybeTrigger()
26 // 
27
28 #ifndef _GC_STRESS_
29 #define _GC_STRESS_
30
31 #include "mpl/type_list"
32
33
34 struct alloc_context;
35
36
37 enum gcs_trigger_points {
38     // generic handling based on EEConfig settings
39     cfg_any,                        // any bit set in EEConfig::iGCStress
40     cfg_alloc,                      // trigger on GC allocations
41     cfg_transition,                 // trigger on transitions
42     cfg_instr_jit,                  // trigger on JITted instructions
43     cfg_instr_ngen,                 // trigger on NGENed instructions
44     cfg_easy,                       // trigger on allocs or transitions
45     cfg_instr,                      // trigger on managed instructions (JITted or NGENed)
46     cfg_last,                       // boundary
47
48     // special handling at particular trigger points
49     jit_on_create_jump_stub,
50     jit_on_create_il_stub,
51     gc_on_alloc,
52     vsd_on_resolve
53 };
54
55
56 namespace GCStressPolicy
57 {
58
59 #ifdef STRESS_HEAP
60
61 #ifdef __GNUC__
62 #define UNUSED_ATTR __attribute__ ((unused))
63 #else  // __GNUC__
64 #define UNUSED_ATTR
65 #endif // __GNUC__
66
67 #ifndef __UNUSED
68 #define __UNUSED(x) ((void)(x))
69 #endif // __UNUSED
70
71     class InhibitHolder
72     {
73     private:
74         // This static controls whether GC stress may induce GCs. EEConfig::GetGCStressLevel() still 
75         // controls when GCs may occur.
76         static Volatile<DWORD> s_nGcStressDisabled;
77
78         bool m_bAquired;
79
80     public:
81         InhibitHolder()
82         { LIMITED_METHOD_CONTRACT; ++s_nGcStressDisabled; m_bAquired = true; }
83
84         ~InhibitHolder()
85         { LIMITED_METHOD_CONTRACT; Release(); }
86
87         void Release()
88         { 
89             LIMITED_METHOD_CONTRACT; 
90             if (m_bAquired)
91             {
92                 --s_nGcStressDisabled;
93                 m_bAquired = false;
94             }
95         }
96
97         friend bool IsEnabled();
98         friend void GlobalDisable();
99         friend void GlobalEnable();
100     } UNUSED_ATTR;
101
102     FORCEINLINE bool IsEnabled()
103     { return InhibitHolder::s_nGcStressDisabled == 0U; }
104
105     FORCEINLINE void GlobalDisable()
106     { ++InhibitHolder::s_nGcStressDisabled; }
107     
108     FORCEINLINE void GlobalEnable()
109     { --InhibitHolder::s_nGcStressDisabled; }
110     
111 #else // STRESS_HEAP
112
113     class InhibitHolder
114     { void Release() {} };
115
116     FORCEINLINE bool IsEnabled()
117     { return false; }
118
119     FORCEINLINE void GlobalDisable()
120     {}
121     
122     FORCEINLINE void GlobalEnable()
123     {}
124
125 #endif // STRESS_HEAP
126 }
127
128
129
130 namespace _GCStress
131 {
132
133 #ifdef STRESS_HEAP
134
135     // Support classes to allow easy customization of GC Stress policies
136     namespace detail
137     {
138         using namespace mpl;
139
140         // Selecting a policy from a type list and a fallback/default policy
141         // GetPolicy<>:type will represent either a type in ListT with the same "tag" as DefPolicy
142         // or DefPolicy, based on the Traits passed in.
143         template <
144             typename ListT, 
145             typename DefPolicy,
146             template <typename> class Traits
147         >
148         struct GetPolicy;
149
150         // Common case: recurse over the type list
151         template <
152             typename HeadT, 
153             typename TailT, 
154             typename DefPolicy,
155             template<typename> class Traits
156         >
157         struct GetPolicy<type_list<HeadT, TailT>, DefPolicy, Traits>
158         {
159             // is true if HeadT and DefPolicy evaluate to the same tag, 
160             // through Traits<>
161             static const bool sameTag = std::is_same<
162                         typename Traits<HeadT>::tag, 
163                         typename Traits<DefPolicy>::tag
164                     >::value;
165
166             typedef typename std::conditional<
167                         sameTag, 
168                         HeadT, 
169                         typename GetPolicy<TailT, DefPolicy, Traits>::type 
170                     >::type type;
171         };
172
173         // Termination case.
174         template <
175             typename DefPolicy,
176             template<typename> class Traits
177         >
178         struct GetPolicy <null_type, DefPolicy, Traits>
179         {
180             typedef DefPolicy type;
181         };
182     }
183
184
185     // GC stress specific EEConfig accessors
186     namespace detail
187     {
188         // no definition provided so that absence of concrete implementations cause compiler errors
189         template <enum gcs_trigger_points>
190         bool IsEnabled();
191
192         template<> FORCEINLINE
193         bool IsEnabled<cfg_any>()
194         {
195             // Most correct would be to test for each specific bits, but we've
196             // always only tested against 0...
197             return g_pConfig->GetGCStressLevel() != 0;
198             // return (g_pConfig->GetGCStressLevel() & 
199             //       (EEConfig::GCSTRESS_ALLOC|EEConfig::GCSTRESS_TRANSITION|
200             //        EEConfig::GCSTRESS_INSTR_JIT|EEConfig::GCSTRESS_INSTR_NGEN) != 0);
201         }
202
203         #define DefineIsEnabled(cfg_enum, eeconfig_bits)                    \
204         template<> FORCEINLINE                                              \
205         bool IsEnabled<cfg_enum>()                                   \
206         {                                                                   \
207             return (g_pConfig->GetGCStressLevel() & (eeconfig_bits)) != 0;  \
208         }
209
210         DefineIsEnabled(cfg_alloc,      EEConfig::GCSTRESS_ALLOC);
211         DefineIsEnabled(cfg_transition, EEConfig::GCSTRESS_TRANSITION);
212         DefineIsEnabled(cfg_instr_jit,  EEConfig::GCSTRESS_INSTR_JIT);
213         DefineIsEnabled(cfg_instr_ngen, EEConfig::GCSTRESS_INSTR_NGEN);
214         DefineIsEnabled(cfg_easy, EEConfig::GCSTRESS_ALLOC|EEConfig::GCSTRESS_TRANSITION);
215         DefineIsEnabled(cfg_instr, EEConfig::GCSTRESS_INSTR_JIT|EEConfig::GCSTRESS_INSTR_NGEN);
216
217         #undef DefineIsEnabled
218
219     }
220
221
222     //
223     // GC stress policy classes used by GCSBase and GCStress template classes
224     //
225
226     // Fast GS stress policies that dictate whether GCStress<>::MaybeTrigger()
227     // will consider g_pConfig->FastGCStressLevel() when deciding whether
228     // to trigger a GC or not.
229
230     // This is the default Fast GC stress policy that ignores the EEConfig
231     // setting
232     class IgnoreFastGcSPolicy
233     {
234     public:
235         FORCEINLINE
236         static bool FastGcSEnabled(DWORD minValue = 0)
237         { return false; }
238     };
239
240     // This is the overriding Fast GC stress policy that considers the 
241     // EEConfig setting on checked/debug builds
242     class EeconfigFastGcSPolicy
243     {
244     public:
245         FORCEINLINE
246         static bool FastGcSEnabled(DWORD minValue = 0)
247         {
248         #ifdef _DEBUG
249             return g_pConfig->FastGCStressLevel() > minValue;
250         #else // _DEBUG
251             return false;
252         #endif // _DEBUG
253         }
254     };
255
256     // GC Mode policies that determines whether to switch the GC mode before
257     // triggering the GC.
258
259     // This is the default GC Mode stress policy that does not switch GC modes
260     class AnyGcModePolicy
261     {
262     };
263
264     // This is the overriding GC Mode stress policy that forces a switch to
265     // cooperative mode before MaybeTrigger() will trigger a GC
266     class CoopGcModePolicy
267     {
268 #ifndef DACCESS_COMPILE
269         // implicit constructor an destructor will do the right thing
270         GCCoop m_coop;
271 #endif // DACCESS_COMPILE
272
273     public:
274         FORCEINLINE CoopGcModePolicy()
275         { WRAPPER_NO_CONTRACT; }
276         FORCEINLINE ~CoopGcModePolicy()
277         { WRAPPER_NO_CONTRACT; }
278     } UNUSED_ATTR;
279
280     // GC Trigger policy classes define how a garbage collection is triggered
281
282     // This is the default GC Trigger policy that simply calls 
283     // IGCHeap::StressHeap
284     class StressGcTriggerPolicy
285     {
286     public:
287         FORCEINLINE
288         static void Trigger()
289         {
290             // BUG(github #10318) - when not using allocation contexts, the alloc lock
291             // must be acquired here. Until fixed, this assert prevents random heap corruption.
292             _ASSERTE(GCHeapUtilities::UseThreadAllocationContexts());
293             GCHeapUtilities::GetGCHeap()->StressHeap(GetThread()->GetAllocContext());
294         }
295
296         FORCEINLINE
297         static void Trigger(::gc_alloc_context* acontext)
298         { GCHeapUtilities::GetGCHeap()->StressHeap(acontext); }
299     };
300
301     // This is an overriding GC Trigger policy that triggers a GC by calling
302     // PulseGCMode
303     class PulseGcTriggerPolicy
304     {
305     public:
306         FORCEINLINE
307         static void Trigger()
308         { 
309             DEBUG_ONLY_REGION();
310             GetThread()->PulseGCMode();
311         }
312     };
313
314
315     // GC stress policy tags
316     struct fast_gcs_policy_tag {};
317     struct gc_mode_policy_tag {};
318     struct gc_trigger_policy_tag {};
319
320
321     template <class GCSPolicy>
322     struct GcStressTraits
323     { typedef mpl::null_type tag; };
324
325     #define DefineGCStressTraits(Policy, policy_tag)                        \
326     template <> struct GcStressTraits<Policy>                               \
327     { typedef policy_tag tag; }
328
329     DefineGCStressTraits(IgnoreFastGcSPolicy, fast_gcs_policy_tag);
330     DefineGCStressTraits(EeconfigFastGcSPolicy, fast_gcs_policy_tag);
331
332     DefineGCStressTraits(AnyGcModePolicy, gc_mode_policy_tag);
333     DefineGCStressTraits(CoopGcModePolicy, gc_mode_policy_tag);
334
335     DefineGCStressTraits(StressGcTriggerPolicy, gc_trigger_policy_tag);
336     DefineGCStressTraits(PulseGcTriggerPolicy, gc_trigger_policy_tag);
337
338     #undef DefineGCStressTraits
339
340     // Special handling for GC stress policies
341     template <class GCPolicies, class DefPolicy>
342     struct GetPolicy:
343         public detail::GetPolicy<GCPolicies, DefPolicy, GcStressTraits>
344     {};
345
346
347     //
348     // The base for any customization GCStress class. It accepts an identifying
349     // GC stress trigger point and at most three overriding policies.
350     //
351     // It defines FastGcSPolicy, GcModePolicy, and GcTriggerPolicy as either
352     // the overriding policy or the default policy, if no corresponding
353     // overriding policy is specified in the list. These names can then be
354     // accessed from the derived GCStress class.
355     //
356     // Additionally it defines the static methods IsEnabled and MaybeTrigger and
357     // how the policy classes influence their behavior. 
358     //
359     template <
360         enum gcs_trigger_points tp, 
361         class Policy1 = mpl::null_type,
362         class Policy2 = mpl::null_type,
363         class Policy3 = mpl::null_type
364     >
365     class GCSBase
366     {
367     public:
368         typedef typename mpl::make_type_list<Policy1, Policy2, Policy3>::type Policies;
369
370         typedef typename GetPolicy<Policies, IgnoreFastGcSPolicy>::type FastGcSPolicy;
371         typedef typename GetPolicy<Policies, AnyGcModePolicy>::type GcModePolicy;
372         typedef typename GetPolicy<Policies, StressGcTriggerPolicy>::type GcTriggerPolicy;
373
374         typedef GCSBase<tp, FastGcSPolicy, GcModePolicy, GcTriggerPolicy> GcStressBase;
375
376         // Returns true iff:
377         //   . the bitflag in EEConfig::GetStressLevel() corresponding to the
378         //     gc stress trigger point is set AND
379         //   . when a Fast GC Stress policy is specified, if the minFastGC argument
380         //     is below the EEConfig::FastGCStressLevel
381         FORCEINLINE
382         static bool IsEnabled(DWORD minFastGc = 0)
383         {
384             static_assert(tp < cfg_last, "GCSBase only supports cfg_ trigger points.");
385             return detail::IsEnabled<tp>() && !FastGcSPolicy::FastGcSEnabled(minFastGc);
386         }
387
388         // Triggers a GC iff 
389         //   . the GC stress is not disabled globally (thru GCStressPolicy::GlobalDisable)
390         //     AND
391         //   . IsEnabled() returns true.
392         // Additionally it switches the GC mode as specified by GcModePolicy, and it 
393         // uses GcTriggerPolicy::Trigger() to actually trigger the GC
394         FORCEINLINE
395         static void MaybeTrigger(DWORD minFastGc = 0)
396         {
397             if (IsEnabled(minFastGc) && GCStressPolicy::IsEnabled())
398             {
399                 GcModePolicy gcModeObj; __UNUSED(gcModeObj); 
400                 GcTriggerPolicy::Trigger();
401             }
402         }
403
404         // Triggers a GC iff 
405         //   . the GC stress is not disabled globally (thru GCStressPolicy::GlobalDisable)
406         //     AND
407         //   . IsEnabled() returns true.
408         // Additionally it switches the GC mode as specified by GcModePolicy, and it 
409         // uses GcTriggerPolicy::Trigger(alloc_context*) to actually trigger the GC
410         FORCEINLINE
411         static void MaybeTrigger(::gc_alloc_context* acontext, DWORD minFastGc = 0)
412         {
413             if (IsEnabled(minFastGc) && GCStressPolicy::IsEnabled())
414             {
415                 GcModePolicy gcModeObj; __UNUSED(gcModeObj); 
416                 GcTriggerPolicy::Trigger(acontext);
417             }
418         }
419     };
420
421     template <
422         enum gcs_trigger_points tp, 
423         class Policy1 = mpl::null_type,
424         class Policy2 = mpl::null_type,
425         class Policy3 = mpl::null_type
426     >
427     class GCStress 
428         : public GCSBase<tp, Policy1, Policy2, Policy3>
429     {
430     };
431
432
433     //
434     // Partial specializations of GCStress for trigger points requiring non-default
435     // handling.
436     //
437
438     template <>
439     class GCStress<jit_on_create_jump_stub>
440         : public GCSBase<cfg_any>
441     {
442     public:
443
444         FORCEINLINE
445         static void MaybeTrigger(DWORD minFastGc = 0)
446         {
447             if ((GetThreadNULLOk() != NULL) && (GetThreadNULLOk()->PreemptiveGCDisabled()))
448             {
449                 // Force a GC if the stress level is high enough
450                 GcStressBase::MaybeTrigger(minFastGc);
451             }
452         }
453
454     };
455
456     template <>
457     class GCStress<gc_on_alloc>
458         : public GCSBase<cfg_alloc>
459     {
460     public:
461
462         FORCEINLINE
463         static void MaybeTrigger(::gc_alloc_context* acontext)
464         {
465             GcStressBase::MaybeTrigger(acontext);
466
467 #ifdef _DEBUG
468             Thread *pThread = GetThread();
469             if (pThread) 
470             {
471                 pThread->EnableStressHeap();
472             }
473 #endif //_DEBUG
474         }
475     };
476
477     template <>
478     class GCStress<vsd_on_resolve>
479         : public GCSBase<cfg_any>
480     {
481     public:
482
483         // Triggers a GC iff 
484         //   . the GC stress is not disabled globally (thru GCStressPolicy::GlobalDisable)
485         //     AND
486         //   . IsEnabled() returns true.
487         // Additionally it protects the passed in OBJECTREF&, and it uses 
488         // GcTriggerPolicy::Trigger() to actually trigger the GC
489         //
490         // Note: the OBJECTREF must be passed by reference so MaybeTrigger can protect 
491         // the calling function's stack slot.
492         FORCEINLINE
493         static void MaybeTriggerAndProtect(OBJECTREF& objref)
494         {
495             if (GcStressBase::IsEnabled() && GCStressPolicy::IsEnabled())
496             {
497                 GCPROTECT_BEGIN(objref);
498                 GcTriggerPolicy::Trigger();
499                 GCPROTECT_END();
500             }
501         }
502     };
503
504 #else // STRESS_HEAP
505
506     class IgnoreFastGcSPolicy {};
507     class EeconfigFastGcSPolicy {};
508     class AnyGcModePolicy {};
509     class CoopGcModePolicy {};
510     class StressGcTriggerPolicy {};
511     class PulseGcTriggerPolicy {};
512
513     // Everything here should resolve to inlined empty blocks or "false"
514     template <
515         enum gcs_trigger_points tp, 
516         class Policy1 = mpl::null_type,
517         class Policy2 = mpl::null_type,
518         class Policy3 = mpl::null_type
519     >
520     class GCStress
521     {
522     public:
523         FORCEINLINE
524         static bool IsEnabled(DWORD minFastGc = 0)
525         { 
526             static_assert(tp < cfg_last, "GCStress::IsEnabled only supports cfg_ trigger points.");
527             return false;
528         }
529
530         FORCEINLINE
531         static void MaybeTrigger(DWORD minFastGc = 0)
532         {}
533
534         FORCEINLINE
535         static void MaybeTrigger(::alloc_context* acontext, DWORD minFastGc = 0)
536         {}
537
538         template<typename T>
539         FORCEINLINE
540         static void MaybeTrigger(T arg)
541         {}
542     };
543
544 #endif // STRESS_HEAP
545
546 }
547
548 using _GCStress::IgnoreFastGcSPolicy;
549 using _GCStress::EeconfigFastGcSPolicy;
550 using _GCStress::AnyGcModePolicy;
551 using _GCStress::CoopGcModePolicy;
552 using _GCStress::StressGcTriggerPolicy;
553 using _GCStress::PulseGcTriggerPolicy;
554
555 using _GCStress::GCStress;
556
557
558
559 #endif