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.
9 // This file provides convenient wrappers for the GC stress functionality.
12 // GCStressPolicy::InhibitHolder
13 // GCStressPolicy::GlobalEnable()
14 // GCStressPolicy::GlobalDisable()
15 // GCStressPolicy::IsEnabled()
17 // GCStress<> template classes with its IsEnabled() & MaybeTrigger members.
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.
24 // GCStress<cfg_any>::IsEnabled()
25 // GCStress<cfg_any, EeconfigFastGcSPolicy, CoopGcModePolicy>::MaybeTrigger()
31 #include "mpl/type_list"
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)
48 // special handling at particular trigger points
49 jit_on_create_jump_stub,
50 jit_on_create_il_stub,
56 namespace GCStressPolicy
62 #define UNUSED_ATTR __attribute__ ((unused))
68 #define __UNUSED(x) ((void)(x))
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;
82 { LIMITED_METHOD_CONTRACT; ++s_nGcStressDisabled; m_bAquired = true; }
85 { LIMITED_METHOD_CONTRACT; Release(); }
89 LIMITED_METHOD_CONTRACT;
92 --s_nGcStressDisabled;
97 friend bool IsEnabled();
98 friend void GlobalDisable();
99 friend void GlobalEnable();
102 FORCEINLINE bool IsEnabled()
103 { return InhibitHolder::s_nGcStressDisabled == 0U; }
105 FORCEINLINE void GlobalDisable()
106 { ++InhibitHolder::s_nGcStressDisabled; }
108 FORCEINLINE void GlobalEnable()
109 { --InhibitHolder::s_nGcStressDisabled; }
114 { void Release() {} };
116 FORCEINLINE bool IsEnabled()
119 FORCEINLINE void GlobalDisable()
122 FORCEINLINE void GlobalEnable()
125 #endif // STRESS_HEAP
135 // Support classes to allow easy customization of GC Stress policies
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.
146 template <typename> class Traits
150 // Common case: recurse over the type list
155 template<typename> class Traits
157 struct GetPolicy<type_list<HeadT, TailT>, DefPolicy, Traits>
159 // is true if HeadT and DefPolicy evaluate to the same tag,
161 static const bool sameTag = std::is_same<
162 typename Traits<HeadT>::tag,
163 typename Traits<DefPolicy>::tag
166 typedef typename std::conditional<
169 typename GetPolicy<TailT, DefPolicy, Traits>::type
176 template<typename> class Traits
178 struct GetPolicy <null_type, DefPolicy, Traits>
180 typedef DefPolicy type;
185 // GC stress specific EEConfig accessors
188 // no definition provided so that absence of concrete implementations cause compiler errors
189 template <enum gcs_trigger_points>
192 template<> FORCEINLINE
193 bool IsEnabled<cfg_any>()
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);
203 #define DefineIsEnabled(cfg_enum, eeconfig_bits) \
204 template<> FORCEINLINE \
205 bool IsEnabled<cfg_enum>() \
207 return (g_pConfig->GetGCStressLevel() & (eeconfig_bits)) != 0; \
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);
217 #undef DefineIsEnabled
223 // GC stress policy classes used by GCSBase and GCStress template classes
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.
230 // This is the default Fast GC stress policy that ignores the EEConfig
232 class IgnoreFastGcSPolicy
236 static bool FastGcSEnabled(DWORD minValue = 0)
240 // This is the overriding Fast GC stress policy that considers the
241 // EEConfig setting on checked/debug builds
242 class EeconfigFastGcSPolicy
246 static bool FastGcSEnabled(DWORD minValue = 0)
249 return g_pConfig->FastGCStressLevel() > minValue;
256 // GC Mode policies that determines whether to switch the GC mode before
257 // triggering the GC.
259 // This is the default GC Mode stress policy that does not switch GC modes
260 class AnyGcModePolicy
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
268 #ifndef DACCESS_COMPILE
269 // implicit constructor an destructor will do the right thing
271 #endif // DACCESS_COMPILE
274 FORCEINLINE CoopGcModePolicy()
275 { WRAPPER_NO_CONTRACT; }
276 FORCEINLINE ~CoopGcModePolicy()
277 { WRAPPER_NO_CONTRACT; }
280 // GC Trigger policy classes define how a garbage collection is triggered
282 // This is the default GC Trigger policy that simply calls
283 // IGCHeap::StressHeap
284 class StressGcTriggerPolicy
288 static void Trigger()
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());
297 static void Trigger(::gc_alloc_context* acontext)
298 { GCHeapUtilities::GetGCHeap()->StressHeap(acontext); }
301 // This is an overriding GC Trigger policy that triggers a GC by calling
303 class PulseGcTriggerPolicy
307 static void Trigger()
310 GetThread()->PulseGCMode();
315 // GC stress policy tags
316 struct fast_gcs_policy_tag {};
317 struct gc_mode_policy_tag {};
318 struct gc_trigger_policy_tag {};
321 template <class GCSPolicy>
322 struct GcStressTraits
323 { typedef mpl::null_type tag; };
325 #define DefineGCStressTraits(Policy, policy_tag) \
326 template <> struct GcStressTraits<Policy> \
327 { typedef policy_tag tag; }
329 DefineGCStressTraits(IgnoreFastGcSPolicy, fast_gcs_policy_tag);
330 DefineGCStressTraits(EeconfigFastGcSPolicy, fast_gcs_policy_tag);
332 DefineGCStressTraits(AnyGcModePolicy, gc_mode_policy_tag);
333 DefineGCStressTraits(CoopGcModePolicy, gc_mode_policy_tag);
335 DefineGCStressTraits(StressGcTriggerPolicy, gc_trigger_policy_tag);
336 DefineGCStressTraits(PulseGcTriggerPolicy, gc_trigger_policy_tag);
338 #undef DefineGCStressTraits
340 // Special handling for GC stress policies
341 template <class GCPolicies, class DefPolicy>
343 public detail::GetPolicy<GCPolicies, DefPolicy, GcStressTraits>
348 // The base for any customization GCStress class. It accepts an identifying
349 // GC stress trigger point and at most three overriding policies.
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.
356 // Additionally it defines the static methods IsEnabled and MaybeTrigger and
357 // how the policy classes influence their behavior.
360 enum gcs_trigger_points tp,
361 class Policy1 = mpl::null_type,
362 class Policy2 = mpl::null_type,
363 class Policy3 = mpl::null_type
368 typedef typename mpl::make_type_list<Policy1, Policy2, Policy3>::type Policies;
370 typedef typename GetPolicy<Policies, IgnoreFastGcSPolicy>::type FastGcSPolicy;
371 typedef typename GetPolicy<Policies, AnyGcModePolicy>::type GcModePolicy;
372 typedef typename GetPolicy<Policies, StressGcTriggerPolicy>::type GcTriggerPolicy;
374 typedef GCSBase<tp, FastGcSPolicy, GcModePolicy, GcTriggerPolicy> GcStressBase;
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
382 static bool IsEnabled(DWORD minFastGc = 0)
384 static_assert(tp < cfg_last, "GCSBase only supports cfg_ trigger points.");
385 return detail::IsEnabled<tp>() && !FastGcSPolicy::FastGcSEnabled(minFastGc);
389 // . the GC stress is not disabled globally (thru GCStressPolicy::GlobalDisable)
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
395 static void MaybeTrigger(DWORD minFastGc = 0)
397 if (IsEnabled(minFastGc) && GCStressPolicy::IsEnabled())
399 GcModePolicy gcModeObj; __UNUSED(gcModeObj);
400 GcTriggerPolicy::Trigger();
405 // . the GC stress is not disabled globally (thru GCStressPolicy::GlobalDisable)
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
411 static void MaybeTrigger(::gc_alloc_context* acontext, DWORD minFastGc = 0)
413 if (IsEnabled(minFastGc) && GCStressPolicy::IsEnabled())
415 GcModePolicy gcModeObj; __UNUSED(gcModeObj);
416 GcTriggerPolicy::Trigger(acontext);
422 enum gcs_trigger_points tp,
423 class Policy1 = mpl::null_type,
424 class Policy2 = mpl::null_type,
425 class Policy3 = mpl::null_type
428 : public GCSBase<tp, Policy1, Policy2, Policy3>
434 // Partial specializations of GCStress for trigger points requiring non-default
439 class GCStress<jit_on_create_jump_stub>
440 : public GCSBase<cfg_any>
445 static void MaybeTrigger(DWORD minFastGc = 0)
447 if ((GetThreadNULLOk() != NULL) && (GetThreadNULLOk()->PreemptiveGCDisabled()))
449 // Force a GC if the stress level is high enough
450 GcStressBase::MaybeTrigger(minFastGc);
457 class GCStress<gc_on_alloc>
458 : public GCSBase<cfg_alloc>
463 static void MaybeTrigger(::gc_alloc_context* acontext)
465 GcStressBase::MaybeTrigger(acontext);
468 Thread *pThread = GetThread();
471 pThread->EnableStressHeap();
478 class GCStress<vsd_on_resolve>
479 : public GCSBase<cfg_any>
484 // . the GC stress is not disabled globally (thru GCStressPolicy::GlobalDisable)
486 // . IsEnabled() returns true.
487 // Additionally it protects the passed in OBJECTREF&, and it uses
488 // GcTriggerPolicy::Trigger() to actually trigger the GC
490 // Note: the OBJECTREF must be passed by reference so MaybeTrigger can protect
491 // the calling function's stack slot.
493 static void MaybeTriggerAndProtect(OBJECTREF& objref)
495 if (GcStressBase::IsEnabled() && GCStressPolicy::IsEnabled())
497 GCPROTECT_BEGIN(objref);
498 GcTriggerPolicy::Trigger();
506 class IgnoreFastGcSPolicy {};
507 class EeconfigFastGcSPolicy {};
508 class AnyGcModePolicy {};
509 class CoopGcModePolicy {};
510 class StressGcTriggerPolicy {};
511 class PulseGcTriggerPolicy {};
513 // Everything here should resolve to inlined empty blocks or "false"
515 enum gcs_trigger_points tp,
516 class Policy1 = mpl::null_type,
517 class Policy2 = mpl::null_type,
518 class Policy3 = mpl::null_type
524 static bool IsEnabled(DWORD minFastGc = 0)
526 static_assert(tp < cfg_last, "GCStress::IsEnabled only supports cfg_ trigger points.");
531 static void MaybeTrigger(DWORD minFastGc = 0)
535 static void MaybeTrigger(::alloc_context* acontext, DWORD minFastGc = 0)
540 static void MaybeTrigger(T arg)
544 #endif // STRESS_HEAP
548 using _GCStress::IgnoreFastGcSPolicy;
549 using _GCStress::EeconfigFastGcSPolicy;
550 using _GCStress::AnyGcModePolicy;
551 using _GCStress::CoopGcModePolicy;
552 using _GCStress::StressGcTriggerPolicy;
553 using _GCStress::PulseGcTriggerPolicy;
555 using _GCStress::GCStress;