diff options
-rw-r--r-- | src/gc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/gc/env/gcenv.ee.h | 4 | ||||
-rw-r--r-- | src/gc/gc.cpp | 209 | ||||
-rw-r--r-- | src/gc/gc.h | 1 | ||||
-rw-r--r-- | src/gc/gccommon.cpp | 53 | ||||
-rw-r--r-- | src/gc/gcconfig.cpp | 48 | ||||
-rw-r--r-- | src/gc/gcconfig.h | 137 | ||||
-rw-r--r-- | src/gc/gcenv.ee.standalone.inl | 25 | ||||
-rw-r--r-- | src/gc/gcinterface.ee.h | 18 | ||||
-rw-r--r-- | src/gc/gcinterface.h | 6 | ||||
-rw-r--r-- | src/gc/gcpriv.h | 55 | ||||
-rw-r--r-- | src/gc/sample/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/gc/sample/gcenv.ee.cpp | 51 | ||||
-rw-r--r-- | src/inc/clrconfigvalues.h | 4 | ||||
-rw-r--r-- | src/vm/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/vm/ceemain.cpp | 2 | ||||
-rw-r--r-- | src/vm/eeconfig.cpp | 8 | ||||
-rw-r--r-- | src/vm/eeconfig.h | 18 | ||||
-rw-r--r-- | src/vm/gcenv.ee.cpp | 122 | ||||
-rw-r--r-- | src/vm/gcenv.ee.h | 4 |
20 files changed, 475 insertions, 293 deletions
diff --git a/src/gc/CMakeLists.txt b/src/gc/CMakeLists.txt index f55c1a9a6f..4de3f4e412 100644 --- a/src/gc/CMakeLists.txt +++ b/src/gc/CMakeLists.txt @@ -11,6 +11,7 @@ if(CLR_CMAKE_PLATFORM_UNIX) endif(CLR_CMAKE_PLATFORM_UNIX) set( GC_SOURCES + gcconfig.cpp gccommon.cpp gcscan.cpp gcsvr.cpp diff --git a/src/gc/env/gcenv.ee.h b/src/gc/env/gcenv.ee.h index aa00d19780..bb335c6834 100644 --- a/src/gc/env/gcenv.ee.h +++ b/src/gc/env/gcenv.ee.h @@ -74,6 +74,10 @@ public: static bool ForceFullGCToBeBlocking(); static bool EagerFinalized(Object* obj); static MethodTable* GetFreeObjectMethodTable(); + static bool GetBooleanConfigValue(const char* key, bool* value); + static bool GetIntConfigValue(const char* key, int64_t* value); + static bool GetStringConfigValue(const char* key, const char** value); + static void FreeStringConfigValue(const char* key); }; #endif // __GCENV_EE_H__ diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp index 653f379b66..662a3b68b4 100644 --- a/src/gc/gc.cpp +++ b/src/gc/gc.cpp @@ -21,7 +21,6 @@ #define USE_INTROSORT - #if defined(BACKGROUND_GC) && defined(FEATURE_EVENT_TRACE) BOOL bgc_heap_walk_for_etw_p = FALSE; #endif //BACKGROUND_GC && FEATURE_EVENT_TRACE @@ -176,7 +175,7 @@ size_t GetHighPrecisionTimeStamp() GCStatistics g_GCStatistics; GCStatistics g_LastGCStatistics; -TCHAR* GCStatistics::logFileName = NULL; +char* GCStatistics::logFileName = NULL; FILE* GCStatistics::logFile = NULL; void GCStatistics::AddGCStats(const gc_mechanisms& settings, size_t timeInMSec) @@ -1424,15 +1423,6 @@ int mark_time, plan_time, sweep_time, reloc_time, compact_time; #endif // MULTIPLE_HEAPS -#ifdef TRACE_GC - -int print_level = DEFAULT_GC_PRN_LVL; //level of detail of the debug trace -BOOL trace_gc = FALSE; -int gc_trace_fac = 0; -hlet* hlet::bindings = 0; - -#endif //TRACE_GC - void reset_memory (uint8_t* o, size_t sizeo); #ifdef WRITE_WATCH @@ -3790,7 +3780,7 @@ public: _ASSERTE(pMT->SanityCheck()); bool noRangeChecks = - (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_NO_RANGE_CHECKS) == EEConfig::HEAPVERIFY_NO_RANGE_CHECKS; + (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_NO_RANGE_CHECKS) == GCConfig::HEAPVERIFY_NO_RANGE_CHECKS; BOOL fSmallObjectHeapPtr = FALSE, fLargeObjectHeapPtr = FALSE; if (!noRangeChecks) @@ -3814,7 +3804,7 @@ public: #endif // FEATURE_64BIT_ALIGNMENT #ifdef VERIFY_HEAP - if (bDeep && (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC)) + if (bDeep && (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC)) g_theGCHeap->ValidateObjectMember(this); #endif if (fSmallObjectHeapPtr) @@ -3905,7 +3895,7 @@ public: //This introduces a bug in the free list management. //((void**) this)[-1] = 0; // clear the sync block, assert (*numComponentsPtr >= 0); - if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + if (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) memset (((uint8_t*)this)+sizeof(ArrayBase), 0xcc, *numComponentsPtr); #endif //VERIFY_HEAP } @@ -4388,12 +4378,12 @@ static size_t get_valid_segment_size (BOOL large_seg=FALSE) if (!large_seg) { initial_seg_size = INITIAL_ALLOC; - seg_size = g_pConfig->GetSegmentSize(); + seg_size = GCConfig::GetSegmentSize(); } else { initial_seg_size = LHEAP_ALLOC; - seg_size = g_pConfig->GetSegmentSize() / 2; + seg_size = GCConfig::GetSegmentSize() / 2; } #ifdef MULTIPLE_HEAPS @@ -5670,7 +5660,7 @@ void gc_mechanisms::first_init() #ifdef BACKGROUND_GC pause_mode = gc_heap::gc_can_use_concurrent ? pause_interactive : pause_batch; #ifdef _DEBUG - int debug_pause_mode = g_pConfig->GetGCLatencyMode(); + int debug_pause_mode = static_cast<int>(GCConfig::GetLatencyMode()); if (debug_pause_mode >= 0) { assert (debug_pause_mode <= pause_sustained_low_latency); @@ -9343,7 +9333,7 @@ void gc_heap::rearrange_large_heap_segments() while (seg) { heap_segment* next_seg = heap_segment_next (seg); - delete_heap_segment (seg, (g_pConfig->GetGCRetainVM() != 0)); + delete_heap_segment (seg, GCConfig::GetRetainVM()); seg = next_seg; } freeable_large_heap_segment = 0; @@ -9386,7 +9376,7 @@ void gc_heap::rearrange_heap_segments(BOOL compacting) assert (prev_seg); assert (seg != ephemeral_heap_segment); heap_segment_next (prev_seg) = next_seg; - delete_heap_segment (seg, (g_pConfig->GetGCRetainVM() != 0)); + delete_heap_segment (seg, GCConfig::GetRetainVM()); dprintf (2, ("Deleting heap segment %Ix", (size_t)seg)); } @@ -9789,28 +9779,20 @@ void gc_heap::adjust_ephemeral_limits () } #if defined(TRACE_GC) || defined(GC_CONFIG_DRIVEN) -FILE* CreateLogFile(const CLRConfig::ConfigStringInfo & info, BOOL is_config) +FILE* CreateLogFile(const GCConfigStringHolder& temp_logfile_name, bool is_config) { FILE* logFile; - TCHAR * temp_logfile_name = NULL; - CLRConfig::GetConfigValue(info, &temp_logfile_name); - TCHAR logfile_name[MAX_LONGPATH+1]; - if (temp_logfile_name != 0) + if (!temp_logfile_name.Get()) { - _tcscpy(logfile_name, temp_logfile_name); + return nullptr; } - size_t logfile_name_len = _tcslen(logfile_name); - TCHAR* szPid = logfile_name + logfile_name_len; - size_t remaining_space = MAX_LONGPATH + 1 - logfile_name_len; - - _stprintf_s(szPid, remaining_space, _T(".%d%s"), GCToOSInterface::GetCurrentProcessId(), (is_config ? _T(".config.log") : _T(".log"))); - - logFile = _tfopen(logfile_name, _T("wb")); - - delete temp_logfile_name; - + char logfile_name[MAX_LONGPATH+1]; + uint32_t pid = GCToOSInterface::GetCurrentProcessId(); + const char* suffix = is_config ? ".config.log" : ".log"; + _snprintf_s(logfile_name, MAX_LONGPATH+1, _TRUNCATE, "%s.%d%s", temp_logfile_name.Get(), pid, suffix); + logFile = fopen(logfile_name, "wb"); return logFile; } #endif //TRACE_GC || GC_CONFIG_DRIVEN @@ -9823,18 +9805,17 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, ) { #ifdef TRACE_GC - int log_last_gcs = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCLogEnabled); - if (log_last_gcs) + if (GCConfig::GetLogEnabled()) { - gc_log = CreateLogFile(CLRConfig::UNSUPPORTED_GCLogFile, FALSE); + gc_log = CreateLogFile(GCConfig::GetLogFile(), false); if (gc_log == NULL) return E_FAIL; // GCLogFileSize in MBs. - gc_log_file_size = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCLogFileSize); + gc_log_file_size = GCConfig::GetLogFileSize(); - if (gc_log_file_size > 500) + if (gc_log_file_size <= 0 || gc_log_file_size > 500) { fclose (gc_log); return E_FAIL; @@ -9855,10 +9836,9 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, #endif // TRACE_GC #ifdef GC_CONFIG_DRIVEN - gc_config_log_on = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCConfigLogEnabled); - if (gc_config_log_on) + if (GCConfig::GetConfigLogEnabled()) { - gc_config_log = CreateLogFile(CLRConfig::UNSUPPORTED_GCConfigLogFile, TRUE); + gc_config_log = CreateLogFile(GCConfig::GetConfigLogFile(), true); if (gc_config_log == NULL) return E_FAIL; @@ -9870,7 +9850,7 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, return E_FAIL; } - compact_ratio = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCCompactRatio); + compact_ratio = static_cast<int>(GCConfig::GetCompactRatio()); // h# | GC | gen | C | EX | NF | BF | ML | DM || PreS | PostS | Merge | Conv | Pre | Post | PrPo | PreP | PostP | cprintf (("%2s | %6s | %1s | %1s | %2s | %2s | %2s | %2s | %2s || %5s | %5s | %5s | %5s | %5s | %5s | %5s | %5s | %5s |", @@ -9897,10 +9877,15 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, #endif //GC_CONFIG_DRIVEN #ifdef GC_STATS - GCStatistics::logFileName = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCMixLog); - if (GCStatistics::logFileName != NULL) + GCConfigStringHolder logFileName = GCConfig::GetMixLogFile(); + if (logFileName.Get() != nullptr) { - GCStatistics::logFile = _tfopen(GCStatistics::logFileName, _T("a")); + GCStatistics::logFileName = _strdup(logFileName.Get()); + GCStatistics::logFile = fopen(GCStatistics::logFileName, "a"); + if (!GCStatistics::logFile) + { + return E_FAIL; + } } #endif // GC_STATS @@ -9909,7 +9894,7 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, #ifdef WRITE_WATCH hardware_write_watch_api_supported(); #ifdef BACKGROUND_GC - if (can_use_write_watch_for_gc_heap() && g_pConfig->GetGCconcurrent() != 0) + if (can_use_write_watch_for_gc_heap() && GCConfig::GetConcurrentGC()) { gc_can_use_concurrent = true; #ifndef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP @@ -10009,11 +9994,6 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, #endif //MULTIPLE_HEAPS -#ifdef TRACE_GC - print_level = g_pConfig->GetGCprnLvl(); - gc_trace_fac = g_pConfig->GetGCtraceFac(); -#endif //TRACE_GC - if (!init_semi_shared()) { hres = E_FAIL; @@ -10095,14 +10075,14 @@ gc_heap::init_semi_shared() should_expand_in_full_gc = FALSE; #ifdef FEATURE_LOH_COMPACTION - loh_compaction_always_p = (g_pConfig->GetGCLOHCompactionMode() != 0); + loh_compaction_always_p = GCConfig::GetLOHCompactionMode() != 0; loh_compaction_mode = loh_compaction_default; #endif //FEATURE_LOH_COMPACTION #ifdef BACKGROUND_GC memset (ephemeral_fgc_counts, 0, sizeof (ephemeral_fgc_counts)); - bgc_alloc_spin_count = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_BGCSpinCount); - bgc_alloc_spin = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_BGCSpin); + bgc_alloc_spin_count = static_cast<uint32_t>(GCConfig::GetBGCSpinCount()); + bgc_alloc_spin = static_cast<uint32_t>(GCConfig::GetBGCSpin()); { int number_bgc_threads = 1; @@ -11534,7 +11514,7 @@ void gc_heap::handle_oom (int heap_num, oom_reason reason, size_t alloc_size, // Break early - before the more_space_lock is release so no other threads // could have allocated on the same heap when OOM happened. - if (g_pConfig->IsGCBreakOnOOMEnabled()) + if (GCConfig::GetBreakOnOOM()) { GCToOSInterface::DebugBreak(); } @@ -11927,7 +11907,7 @@ void gc_heap::bgc_loh_alloc_clr (uint8_t* alloc_start, #ifdef VERIFY_HEAP // since we filled in 0xcc for free object when we verify heap, // we need to make sure we clear those bytes. - if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + if (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) { if (size_to_clear < saved_size_to_clear) { @@ -13136,7 +13116,7 @@ int gc_heap::try_allocate_more_space (alloc_context* acontext, size_t size, #ifdef SYNCHRONIZATION_STATS good_suspension++; #endif //SYNCHRONIZATION_STATS - BOOL fStress = (g_pConfig->GetGCStressLevel() & EEConfig::GCSTRESS_TRANSITION) != 0; + BOOL fStress = (g_pConfig->GetGCStressLevel() & GCConfig::GCSTRESS_TRANSITION) != 0; if (!fStress) { //Rendez vous early (MP scaling issue) @@ -14484,6 +14464,8 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation, // We can only do Concurrent GC Stress if the caller did not explicitly ask for all // generations to be collected, + // [LOCALGC TODO] STRESS_HEAP is not defined for a standalone GC so there are multiple + // things that need to be fixed in this code block. if (n_original != max_generation && g_pConfig->GetGCStressLevel() && gc_can_use_concurrent) { @@ -15543,7 +15525,6 @@ void gc_heap::gc1() } descr_generations (FALSE); - descr_card_table(); verify_soh_segment_list(); @@ -15577,7 +15558,7 @@ void gc_heap::gc1() // value. If we ever allow randomly adjusting this as the process runs, // we cannot call it this way as joins need to match - we must have the same // value for all heaps like we do with bgc_heap_walk_for_etw_p. - || (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + || (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) #endif #if defined(FEATURE_EVENT_TRACE) && defined(BACKGROUND_GC) || (bgc_heap_walk_for_etw_p && settings.concurrent) @@ -15639,7 +15620,7 @@ void gc_heap::gc1() #endif //BACKGROUND_GC #ifdef VERIFY_HEAP - if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + if (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) verify_heap (FALSE); #endif // VERIFY_HEAP @@ -16594,14 +16575,6 @@ int gc_heap::garbage_collect (int n) if (gc_t_join.joined()) #endif //MULTIPLE_HEAPS { -#ifdef TRACE_GC - int gc_count = (int)dd_collection_count (dynamic_data_of (0)); - if (gc_count >= g_pConfig->GetGCtraceStart()) - trace_gc = 1; - if (gc_count >= g_pConfig->GetGCtraceEnd()) - trace_gc = 0; -#endif //TRACE_GC - #ifdef MULTIPLE_HEAPS #if !defined(SEG_MAPPING_TABLE) && !defined(FEATURE_BASICFREEZE) //delete old slots from the segment table @@ -16748,12 +16721,12 @@ int gc_heap::garbage_collect (int n) // descr_card_table(); #ifdef VERIFY_HEAP - if ((g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) && - !(g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_POST_GC_ONLY)) + if ((GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) && + !(GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_POST_GC_ONLY)) { verify_heap (TRUE); } - if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_BARRIERCHECK) + if (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_BARRIERCHECK) checkGCWriteBarrier(); #endif // VERIFY_HEAP @@ -17125,7 +17098,7 @@ uint8_t* gc_heap::find_object (uint8_t* interior, uint8_t* low) heap_segment* seg = find_segment_per_heap (interior, FALSE); if (seg #ifdef FEATURE_CONSERVATIVE_GC - && (!g_pConfig->GetGCConservative() || interior <= heap_segment_allocated(seg)) + && (GCConfig::GetConservativeGC() || interior <= heap_segment_allocated(seg)) #endif ) { @@ -17133,7 +17106,7 @@ uint8_t* gc_heap::find_object (uint8_t* interior, uint8_t* low) // we don't have brick entry for it, and we may incorrectly treat it as on large object heap. int align_const = get_alignment_constant (heap_segment_read_only_p (seg) #ifdef FEATURE_CONSERVATIVE_GC - || (g_pConfig->GetGCConservative() && !heap_segment_loh_p (seg)) + || (GCConfig::GetConservativeGC() && !heap_segment_loh_p (seg)) #endif ); //int align_const = get_alignment_constant (heap_segment_read_only_p (seg)); @@ -18603,7 +18576,7 @@ void gc_heap::background_promote (Object** ppObject, ScanContext* sc, uint32_t f #ifdef FEATURE_CONSERVATIVE_GC // For conservative GC, a value on stack may point to middle of a free object. // In this case, we don't need to promote the pointer. - if (g_pConfig->GetGCConservative() && ((CObjectHeader*)o)->IsFree()) + if (GCConfig::GetConservativeGC() && ((CObjectHeader*)o)->IsFree()) { return; } @@ -23714,7 +23687,7 @@ void gc_heap::relocate_survivor_helper (uint8_t* plug, uint8_t* plug_end) void gc_heap::verify_pins_with_post_plug_info (const char* msg) { #if defined (_DEBUG) && defined (VERIFY_HEAP) - if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + if (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) { if (!verify_pinned_queue_p) return; @@ -26596,7 +26569,7 @@ void gc_heap::background_promote_callback (Object** ppObject, ScanContext* sc, #ifdef FEATURE_CONSERVATIVE_GC // For conservative GC, a value on stack may point to middle of a free object. // In this case, we don't need to promote the pointer. - if (g_pConfig->GetGCConservative() && ((CObjectHeader*)o)->IsFree()) + if (GCConfig::GetConservativeGC() && ((CObjectHeader*)o)->IsFree()) { return; } @@ -29192,7 +29165,7 @@ gc_heap::realloc_plugs (generation* consing_gen, heap_segment* seg, void gc_heap::verify_no_pins (uint8_t* start, uint8_t* end) { #ifdef VERIFY_HEAP - if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + if (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) { BOOL contains_pinned_plugs = FALSE; size_t mi = 0; @@ -30259,7 +30232,7 @@ BOOL gc_heap::decide_on_compacting (int condemned_gen_number, #endif // GC_STATS #endif //STRESS_HEAP - if (g_pConfig->GetGCForceCompact()) + if (GCConfig::GetForceCompact()) should_compact = TRUE; if ((condemned_gen_number == max_generation) && last_gc_before_oom) @@ -30596,7 +30569,7 @@ CObjectHeader* gc_heap::allocate_large_object (size_t jsize, int64_t& alloc_byte if (jsize >= maxObjectSize) { - if (g_pConfig->IsGCBreakOnOOMEnabled()) + if (GCConfig::GetBreakOnOOM()) { GCToOSInterface::DebugBreak(); } @@ -30822,8 +30795,8 @@ void gc_heap::set_mem_verify (uint8_t* start, uint8_t* end, uint8_t b) #ifdef VERIFY_HEAP if (end > start) { - if ((g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) && - !(g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_NO_MEM_FILL)) + if ((GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) && + !(GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_NO_MEM_FILL)) { dprintf (3, ("setting mem to %c [%Ix, [%Ix", b, start, end)); memset (start, b, (end - start)); @@ -31182,7 +31155,7 @@ void gc_heap::background_ephemeral_sweep() // the following line is temporary. heap_segment_saved_bg_allocated (ephemeral_heap_segment) = plug_end; #ifdef VERIFY_HEAP - if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + if (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) { make_unused_array (plug_end, (end - plug_end)); } @@ -31982,36 +31955,6 @@ void gc_heap::descr_segment (heap_segment* seg ) #endif // TRACE_GC } -void gc_heap::descr_card_table () -{ -#ifdef TRACE_GC - if (trace_gc && (print_level >= 4)) - { - ptrdiff_t min = -1; - dprintf(3,("Card Table set at: ")); - for (size_t i = card_of (lowest_address); i < card_of (highest_address); i++) - { - if (card_set_p (i)) - { - if (min == -1) - { - min = i; - } - } - else - { - if (! ((min == -1))) - { - dprintf (3,("[%Ix %Ix[, ", - (size_t)card_address (min), (size_t)card_address (i))); - min = -1; - } - } - } - } -#endif //TRACE_GC -} - void gc_heap::descr_generations_to_profiler (gen_walk_fn fn, void *context) { #ifdef MULTIPLE_HEAPS @@ -32395,7 +32338,7 @@ BOOL gc_heap::bgc_mark_array_range (heap_segment* seg, void gc_heap::bgc_verify_mark_array_cleared (heap_segment* seg) { #if defined (VERIFY_HEAP) && defined (MARK_ARRAY) - if (recursive_gc_sync::background_running_p() && g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + if (recursive_gc_sync::background_running_p() && GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) { uint8_t* range_beg = 0; uint8_t* range_end = 0; @@ -32579,7 +32522,7 @@ void gc_heap::verify_mark_array_cleared (heap_segment* seg) void gc_heap::verify_mark_array_cleared () { #if defined (VERIFY_HEAP) && defined (MARK_ARRAY) - if (recursive_gc_sync::background_running_p() && g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + if (recursive_gc_sync::background_running_p() && GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) { generation* gen = generation_of (max_generation); heap_segment* seg = heap_segment_rw (generation_start_segment (gen)); @@ -32609,7 +32552,7 @@ void gc_heap::verify_mark_array_cleared () void gc_heap::verify_seg_end_mark_array_cleared() { #if defined (VERIFY_HEAP) && defined (MARK_ARRAY) - if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + if (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) { generation* gen = generation_of (max_generation); heap_segment* seg = heap_segment_rw (generation_start_segment (gen)); @@ -32671,7 +32614,7 @@ void gc_heap::verify_seg_end_mark_array_cleared() void gc_heap::verify_soh_segment_list() { #ifdef VERIFY_HEAP - if (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC) + if (GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_GC) { generation* gen = generation_of (max_generation); heap_segment* seg = heap_segment_rw (generation_start_segment (gen)); @@ -32857,7 +32800,7 @@ gc_heap::verify_free_lists () void gc_heap::verify_heap (BOOL begin_gc_p) { - int heap_verify_level = g_pConfig->GetHeapVerifyLevel(); + int heap_verify_level = static_cast<int>(GCConfig::GetHeapVerifyLevel()); size_t last_valid_brick = 0; BOOL bCurrentBrickInvalid = FALSE; BOOL large_brick_p = TRUE; @@ -32919,7 +32862,7 @@ gc_heap::verify_heap (BOOL begin_gc_p) if (!settings.concurrent) #endif //BACKGROUND_GC { - if (!(heap_verify_level & EEConfig::HEAPVERIFY_NO_MEM_FILL)) + if (!(heap_verify_level & GCConfig::HEAPVERIFY_NO_MEM_FILL)) { //uninit the unused portions of segments. generation* gen1 = large_object_generation; @@ -33199,7 +33142,7 @@ gc_heap::verify_heap (BOOL begin_gc_p) #endif //BACKGROUND_GC BOOL deep_verify_obj = can_verify_deep; - if ((heap_verify_level & EEConfig::HEAPVERIFY_DEEP_ON_COMPACT) && !settings.compaction) + if ((heap_verify_level & GCConfig::HEAPVERIFY_DEEP_ON_COMPACT) && !settings.compaction) deep_verify_obj = FALSE; ((CObjectHeader*)curr_object)->ValidateHeap((Object*)curr_object, deep_verify_obj); @@ -33492,6 +33435,7 @@ HRESULT GCHeap::Initialize () return E_FAIL; } + g_gc_pFreeObjectMethodTable = GCToEEInterface::GetFreeObjectMethodTable(); //Initialize the static members. @@ -33507,10 +33451,10 @@ HRESULT GCHeap::Initialize () gc_heap::min_segment_size = min (seg_size, large_seg_size); #ifdef MULTIPLE_HEAPS - if (g_pConfig->GetGCNoAffinitize()) + if (GCConfig::GetNoAffinitize()) gc_heap::gc_thread_no_affinitize_p = true; - uint32_t nhp_from_config = g_pConfig->GetGCHeapCount(); + uint32_t nhp_from_config = static_cast<uint32_t>(GCConfig::GetHeapCount()); // GetGCProcessCpuCount only returns up to 64 procs. uint32_t nhp_from_process = CPUGroupInfo::CanEnableGCCPUGroups() ? CPUGroupInfo::GetNumActiveProcessors(): @@ -33813,7 +33757,7 @@ void GCHeap::Promote(Object** ppObject, ScanContext* sc, uint32_t flags) #ifdef FEATURE_CONSERVATIVE_GC // For conservative GC, a value on stack may point to middle of a free object. // In this case, we don't need to promote the pointer. - if (g_pConfig->GetGCConservative() + if (GCConfig::GetConservativeGC() && ((CObjectHeader*)o)->IsFree()) { return; @@ -34086,14 +34030,7 @@ bool GCHeap::StressHeap(gc_alloc_context * context) str->SetMethodTable (g_pStringClass); str->SetStringLength (strLen); -#if CHECK_APP_DOMAIN_LEAKS - if (g_pConfig->AppDomainLeaks() && str->SetAppDomainNoThrow()) - { -#endif - HndAssignHandle(m_StressObjs[i], ObjectToOBJECTREF(str)); -#if CHECK_APP_DOMAIN_LEAKS - } -#endif + HndAssignHandle(m_StressObjs[i], ObjectToOBJECTREF(str)); } i = (i + 1) % NUM_HEAP_STRESS_OBJS; if (i == m_CurStressObj) break; @@ -35510,7 +35447,7 @@ size_t GCHeap::GetValidSegmentSize(bool large_seg) // Get the max gen0 heap size, making sure it conforms. size_t GCHeap::GetValidGen0MaxSize(size_t seg_size) { - size_t gen0size = g_pConfig->GetGCgen0size(); + size_t gen0size = GCConfig::GetGen0Size(); if ((gen0size == 0) || !g_theGCHeap->IsValidGen0MaxSize(gen0size)) { @@ -35716,7 +35653,7 @@ bool CFinalize::Initialize() { ASSERT (m_Array); STRESS_LOG_OOM_STACK(sizeof(Object*[100])); - if (g_pConfig->IsGCBreakOnOOMEnabled()) + if (GCConfig::GetBreakOnOOM()) { GCToOSInterface::DebugBreak(); } @@ -35825,7 +35762,7 @@ CFinalize::RegisterForFinalization (int gen, Object* obj, size_t size) ((CObjectHeader*)obj)->SetFree(size); } STRESS_LOG_OOM_STACK(0); - if (g_pConfig->IsGCBreakOnOOMEnabled()) + if (GCConfig::GetBreakOnOOM()) { GCToOSInterface::DebugBreak(); } @@ -36506,7 +36443,7 @@ void deleteGCShadow() // Called at startup and right after a GC, get a snapshot of the GC Heap void initGCShadow() { - if (!(g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_BARRIERCHECK)) + if (!(GCConfig::GetHeapVerifyLevel() & GCConfig::HEAPVERIFY_BARRIERCHECK)) return; size_t len = g_gc_highest_address - g_gc_lowest_address; diff --git a/src/gc/gc.h b/src/gc/gc.h index 2da0cb3966..64c287e8be 100644 --- a/src/gc/gc.h +++ b/src/gc/gc.h @@ -38,6 +38,7 @@ Module Name: #else #include "env/gcenv.ee.h" #endif // BUILD_AS_STANDALONE +#include "gcconfig.h" /* * Promotion Function Prototypes diff --git a/src/gc/gccommon.cpp b/src/gc/gccommon.cpp index d7c572260a..1e5383843b 100644 --- a/src/gc/gccommon.cpp +++ b/src/gc/gccommon.cpp @@ -113,26 +113,6 @@ void record_changed_seg (uint8_t* start, uint8_t* end, } } -// The runtime needs to know whether we're using workstation or server GC -// long before the GCHeap is created. -void InitializeHeapType(bool bServerHeap) -{ - LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_SVR_GC - g_gc_heap_type = bServerHeap ? GC_HEAP_SVR : GC_HEAP_WKS; -#ifdef WRITE_BARRIER_CHECK - if (g_gc_heap_type == GC_HEAP_SVR) - { - g_GCShadow = 0; - g_GCShadowEnd = 0; - } -#endif // WRITE_BARRIER_CHECK -#else // FEATURE_SVR_GC - UNREFERENCED_PARAMETER(bServerHeap); - CONSISTENCY_CHECK(bServerHeap == false); -#endif // FEATURE_SVR_GC -} - namespace WKS { extern void PopulateDacVars(GcDacVars* dacVars); @@ -176,6 +156,18 @@ InitializeGarbageCollector( assert(gcHeap != nullptr); assert(gcHandleManager != nullptr); +#ifdef BUILD_AS_STANDALONE + assert(clrToGC != nullptr); + g_theGCToCLR = clrToGC; +#else + UNREFERENCED_PARAMETER(clrToGC); + assert(clrToGC == nullptr); +#endif + + // Initialize GCConfig before anything else - initialization of our + // various components may want to query the current configuration. + GCConfig::Initialize(); + IGCHandleManager* handleManager = CreateGCHandleManager(); if (handleManager == nullptr) { @@ -183,19 +175,25 @@ InitializeGarbageCollector( } #ifdef FEATURE_SVR_GC - assert(g_gc_heap_type != GC_HEAP_INVALID); - - if (g_gc_heap_type == GC_HEAP_SVR) + if (GCConfig::GetServerGC()) { +#ifdef WRITE_BARRIER_CHECK + g_GCShadow = 0; + g_GCShadowEnd = 0; +#endif // WRITE_BARRIER_CHECK + + g_gc_heap_type = GC_HEAP_SVR; heap = SVR::CreateGCHeap(); SVR::PopulateDacVars(gcDacVars); } else { + g_gc_heap_type = GC_HEAP_WKS; heap = WKS::CreateGCHeap(); WKS::PopulateDacVars(gcDacVars); } #else + g_gc_heap_type = GC_HEAP_WKS; heap = WKS::CreateGCHeap(); WKS::PopulateDacVars(gcDacVars); #endif @@ -206,15 +204,6 @@ InitializeGarbageCollector( } g_theGCHeap = heap; - -#ifdef BUILD_AS_STANDALONE - assert(clrToGC != nullptr); - g_theGCToCLR = clrToGC; -#else - UNREFERENCED_PARAMETER(clrToGC); - assert(clrToGC == nullptr); -#endif - *gcHandleManager = handleManager; *gcHeap = heap; return true; diff --git a/src/gc/gcconfig.cpp b/src/gc/gcconfig.cpp new file mode 100644 index 0000000000..d84a5a5801 --- /dev/null +++ b/src/gc/gcconfig.cpp @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "common.h" +#include "gcenv.h" +#include "gc.h" + +#define BOOL_CONFIG(name, key, default, unused_doc) \ + bool GCConfig::Get##name() { return s_##name; } \ + bool GCConfig::s_##name = default; + +#define INT_CONFIG(name, key, default, unused_doc) \ + int64_t GCConfig::Get##name() { return s_##name; } \ + int64_t GCConfig::s_##name = default; + +// String configs are not cached because 1) they are rare and +// not on hot paths and 2) they involve transfers of ownership +// of EE-allocated strings, which is potentially complicated. +#define STRING_CONFIG(name, key, unused_doc) \ + GCConfigStringHolder GCConfig::Get##name() \ + { \ + const char* resultStr = nullptr; \ + GCToEEInterface::GetStringConfigValue(key, &resultStr); \ + return GCConfigStringHolder(resultStr); \ + } + +GC_CONFIGURATION_KEYS + +#undef BOOL_CONFIG +#undef INT_CONFIG +#undef STRING_CONFIG + +void GCConfig::Initialize() +{ +#define BOOL_CONFIG(name, key, default, unused_doc) \ + GCToEEInterface::GetBooleanConfigValue(key, &s_##name); + +#define INT_CONFIG(name, key, default, unused_doc) \ + GCToEEInterface::GetIntConfigValue(key, &s_##name); + +#define STRING_CONFIG(unused_name, unused_key, unused_doc) + +GC_CONFIGURATION_KEYS + +#undef BOOL_CONFIG +#undef INT_CONFIG +} diff --git a/src/gc/gcconfig.h b/src/gc/gcconfig.h new file mode 100644 index 0000000000..3a95857430 --- /dev/null +++ b/src/gc/gcconfig.h @@ -0,0 +1,137 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef __GCCONFIG_H__ +#define __GCCONFIG_H__ + +// gcconfig.h - GC configuration management and retrieval. +// +// This file and the GCConfig class are designed to be the primary entry point +// for querying configuration information from within the GC. + +// GCConfigStringHolder is a wrapper around a configuration string obtained +// from the EE. Such strings must be disposed using GCToEEInterface::FreeStringConfigValue, +// so this class ensures that is done correctly. +// +// The name is unfortunately a little long, but "ConfigStringHolder" is already taken by the +// EE's config mechanism. +class GCConfigStringHolder +{ +private: + const char* m_str; + +public: + // Constructs a new GCConfigStringHolder around a string obtained from + // GCToEEInterface::GetStringConfigValue. + explicit GCConfigStringHolder(const char* str) + : m_str(str) {} + + // No copy operators - this type cannot be copied. + GCConfigStringHolder(const GCConfigStringHolder&) = delete; + GCConfigStringHolder& operator=(const GCConfigStringHolder&) = delete; + + // This type is returned by-value by string config functions, so it + // requires a move constructor. + GCConfigStringHolder(GCConfigStringHolder&&) = default; + + // Frees a string config value by delegating to GCToEEInterface::FreeStringConfigValue. + ~GCConfigStringHolder() + { + if (m_str) + { + GCToEEInterface::FreeStringConfigValue(m_str); + } + + m_str = nullptr; + } + + // Retrieves the wrapped config string. + const char* Get() const { return m_str; } +}; + +// Each one of these keys produces a method on GCConfig with the name "Get{name}", where {name} +// is the first parameter of the *_CONFIG macros below. +#define GC_CONFIGURATION_KEYS \ + BOOL_CONFIG(ServerGC, "gcServer", false, "Whether we should be using Server GC") \ + BOOL_CONFIG(ConcurrentGC, "gcConcurrent", true, "Whether we should be using Concurrent GC") \ + BOOL_CONFIG(ConservativeGC, "gcConservative", false, "Enables/Disables conservative GC") \ + BOOL_CONFIG(ForceCompact, "gcForceCompact", false, \ + "When set to true, always do compacting GC") \ + BOOL_CONFIG(RetainVM, "GCRetainVM", false, \ + "When set we put the segments that should be deleted on a standby list (instead of " \ + "releasing them back to the OS) which will be considered to satisfy new segment requests"\ + " (note that the same thing can be specified via API which is the supported way)") \ + BOOL_CONFIG(StressMix, "GCStressMix", false, \ + "Specifies whether the GC mix mode is enabled or not") \ + BOOL_CONFIG(BreakOnOOM, "GCBreakOnOOM", false, \ + "Does a DebugBreak at the soonest time we detect an OOM") \ + BOOL_CONFIG(NoAffinitize, "GCNoAffinitize", false, \ + "If set, do not affinitize server GC threads") \ + BOOL_CONFIG(LogEnabled, "GCLogEnabled", false, \ + "Specifies if you want to turn on logging in GC") \ + BOOL_CONFIG(ConfigLogEnabled, "GCConfigLogEnabled", false, \ + "Specifies the name of the GC config log file") \ + INT_CONFIG(HeapVerifyLevel, "HeapVerify", HEAPVERIFY_NONE, \ + "When set verifies the integrity of the managed heap on entry and exit of each GC") \ + INT_CONFIG(LOHCompactionMode, "GCLOHCompact", 0, "Specifies the LOH compaction mode") \ + INT_CONFIG(BGCSpinCount, "BGCSpinCount", 140, "Specifies the bgc spin count") \ + INT_CONFIG(BGCSpin, "BGCSpin", 2, "Specifies the bgc spin time") \ + INT_CONFIG(HeapCount, "GCHeapCount", 0, "Specifies the number of server GC heaps") \ + INT_CONFIG(Gen0Size, "GCgen0size", 0, "Specifies the smallest gen0 size") \ + INT_CONFIG(SegmentSize, "GCSegmentSize", 0, "Specifies the managed heap segment size") \ + INT_CONFIG(LatencyMode, "GCLatencyMode", -1, \ + "Specifies the GC latency mode - batch, interactive or low latency (note that the same " \ + "thing can be specified via API which is the supported way") \ + INT_CONFIG(LogFileSize, "GCLogFileSize", 0, "Specifies the GC log file size") \ + INT_CONFIG(CompactRatio, "GCCompactRatio", 0, \ + "Specifies the ratio compacting GCs vs sweeping") \ + STRING_CONFIG(LogFile, "GCLogFile", "Specifies the name of the GC log file") \ + STRING_CONFIG(ConfigLogFile, "GCConfigLogFile", \ + "Specifies the name of the GC config log file") \ + STRING_CONFIG(MixLogFile, "GCMixLog", \ + "Specifies the name of the log file for GC mix statistics") + +// This class is responsible for retreiving configuration information +// for how the GC should operate. +class GCConfig +{ +#define BOOL_CONFIG(name, unused_key, unused_default, unused_doc) \ + public: static bool Get##name(); \ + private: static bool s_##name; +#define INT_CONFIG(name, unused_key, unused_default, unused_doc) \ + public: static int64_t Get##name(); \ + private: static int64_t s_##name; +#define STRING_CONFIG(name, unused_key, unused_doc) \ + public: static GCConfigStringHolder Get##name(); +GC_CONFIGURATION_KEYS +#undef BOOL_CONFIG +#undef INT_CONFIG +#undef STRING_CONFIG + +public: +// Flags that may inhabit the number returned for the HeapVerifyLevel config option. +// Keep this in sync with vm\eeconfig.h if this ever changes. +enum HeapVerifyFlags { + HEAPVERIFY_NONE = 0, + HEAPVERIFY_GC = 1, // Verify the heap at beginning and end of GC + HEAPVERIFY_BARRIERCHECK = 2, // Verify the brick table + HEAPVERIFY_SYNCBLK = 4, // Verify sync block scanning + + // the following options can be used to mitigate some of the overhead introduced + // by heap verification. some options might cause heap verifiction to be less + // effective depending on the scenario. + + HEAPVERIFY_NO_RANGE_CHECKS = 0x10, // Excludes checking if an OBJECTREF is within the bounds of the managed heap + HEAPVERIFY_NO_MEM_FILL = 0x20, // Excludes filling unused segment portions with fill pattern + HEAPVERIFY_POST_GC_ONLY = 0x40, // Performs heap verification post-GCs only (instead of before and after each GC) + HEAPVERIFY_DEEP_ON_COMPACT = 0x80 // Performs deep object verfication only on compacting GCs. +}; + +// Initializes the GCConfig subsystem. Must be called before accessing any +// configuration information. +static void Initialize(); + +}; + +#endif // __GCCONFIG_H__ diff --git a/src/gc/gcenv.ee.standalone.inl b/src/gc/gcenv.ee.standalone.inl index 31c3455d7b..642d150976 100644 --- a/src/gc/gcenv.ee.standalone.inl +++ b/src/gc/gcenv.ee.standalone.inl @@ -241,6 +241,31 @@ ALWAYS_INLINE MethodTable* GCToEEInterface::GetFreeObjectMethodTable() assert(g_theGCToCLR != nullptr); return g_theGCToCLR->GetFreeObjectMethodTable(); } + +ALWAYS_INLINE bool GCToEEInterface::GetBooleanConfigValue(const char* key, bool* value) +{ + assert(g_theGCToCLR != nullptr); + return g_theGCToCLR->GetBooleanConfigValue(key, value); +} + +ALWAYS_INLINE bool GCToEEInterface::GetIntConfigValue(const char* key, int64_t* value) +{ + assert(g_theGCToCLR != nullptr); + return g_theGCToCLR->GetIntConfigValue(key, value); +} + +ALWAYS_INLINE bool GCToEEInterface::GetStringConfigValue(const char* key, const char** value) +{ + assert(g_theGCToCLR != nullptr); + return g_theGCToCLR->GetStringConfigValue(key, value); +} + +ALWAYS_INLINE void GCToEEInterface::FreeStringConfigValue(const char* value) +{ + assert(g_theGCToCLR != nullptr); + g_theGCToCLR->FreeStringConfigValue(value); +} + #undef ALWAYS_INLINE } // anonymous namespace diff --git a/src/gc/gcinterface.ee.h b/src/gc/gcinterface.ee.h index 8290572cd4..32dcc039ef 100644 --- a/src/gc/gcinterface.ee.h +++ b/src/gc/gcinterface.ee.h @@ -18,7 +18,7 @@ public: // Suspends the EE for the given reason. virtual void SuspendEE(SUSPEND_REASON reason) = 0; - + // Resumes all paused threads, with a boolean indicating // if the EE is being restarted because a GC is complete. virtual @@ -166,6 +166,22 @@ public: // field to see how many bytes to skip before the next object on a heap segment begins. virtual MethodTable* GetFreeObjectMethodTable() = 0; + + // Asks the EE for the value of a given configuration key. If the EE does not know or does not + // have a value for the requeested config key, false is returned and the value of the passed-in + // pointer is undefined. Otherwise, true is returned and the config key's value is written to + // the passed-in pointer. + virtual + bool GetBooleanConfigValue(const char* key, bool* value) = 0; + + virtual + bool GetIntConfigValue(const char* key, int64_t* value) = 0; + + virtual + bool GetStringConfigValue(const char* key, const char** value) = 0; + + virtual + void FreeStringConfigValue(const char* value) = 0; }; #endif // _GCINTERFACE_EE_H_ diff --git a/src/gc/gcinterface.h b/src/gc/gcinterface.h index 3eb332c312..aefa84b99b 100644 --- a/src/gc/gcinterface.h +++ b/src/gc/gcinterface.h @@ -185,12 +185,6 @@ typedef bool (*InitializeGarbageCollectorFunction)( // to be used as an argument to GetProcAddress. #define INITIALIZE_GC_FUNCTION_NAME "InitializeGarbageCollector" -// The runtime needs to know whether we're using workstation or server GC -// long before the GCHeap is created. This function sets the type of -// heap that will be created, before InitializeGarbageCollector is called -// and the heap is actually created. -void InitializeHeapType(bool bServerHeap); - #ifdef WRITE_BARRIER_CHECK //always defined, but should be 0 in Server GC extern uint8_t* g_GCShadow; diff --git a/src/gc/gcpriv.h b/src/gc/gcpriv.h index 9f098ebe3b..08fedbbde3 100644 --- a/src/gc/gcpriv.h +++ b/src/gc/gcpriv.h @@ -234,46 +234,6 @@ const int policy_compact = 1; const int policy_expand = 2; #ifdef TRACE_GC - - -extern int print_level; -extern BOOL trace_gc; -extern int gc_trace_fac; - - -class hlet -{ - static hlet* bindings; - int prev_val; - int* pval; - hlet* prev_let; -public: - hlet (int& place, int value) - { - prev_val = place; - pval = &place; - place = value; - prev_let = bindings; - bindings = this; - } - ~hlet () - { - *pval = prev_val; - bindings = prev_let; - } -}; - - -#define let(p,v) hlet __x = hlet (p, v); - -#else //TRACE_GC - -#define gc_count -1 -#define let(s,v) - -#endif //TRACE_GC - -#ifdef TRACE_GC #define SEG_REUSE_LOG_0 7 #define SEG_REUSE_LOG_1 (SEG_REUSE_LOG_0 + 1) #define DT_LOG_0 (SEG_REUSE_LOG_1 + 1) @@ -299,15 +259,12 @@ void GCLog (const char *fmt, ... ); //#define dprintf(l,x) {if ((l==GTC_LOG) || (l <= 1)) {GCLog x;}} //#define dprintf(l,x) {if (trace_gc && ((l <= print_level) || (l==GTC_LOG))) {GCLog x;}} //#define dprintf(l,x) {if (l==GTC_LOG) {printf ("\n");printf x ; fflush(stdout);}} -#else //SIMPLE_DPRINTF +#else -// The GCTrace output goes to stdout by default but can get sent to the stress log or the logfile if the -// reg key GCTraceFacility is set. THe stress log can only take a format string and 4 numbers or -// string literals. -#define dprintf(l,x) {if (trace_gc && (l<=print_level)) { \ - if ( !gc_trace_fac) {printf ("\n");printf x ; fflush(stdout);} \ - else if ( gc_trace_fac == 2) {LogSpewAlways x;LogSpewAlways ("\n");} \ - else if ( gc_trace_fac == 1) {STRESS_LOG_VA(x);}}} +// Nobody used the logging mechanism that used to be here. If we find ourselves +// wanting to inspect GC logs on unmodified builds, we can use this define here +// to do so. +#define dprintf(l, x) #endif //SIMPLE_DPRINTF @@ -602,7 +559,7 @@ struct GCStatistics : public StatisticsBase { // initialized to the contents of COMPlus_GcMixLog, or NULL, if not present - static TCHAR* logFileName; + static char* logFileName; static FILE* logFile; // number of times we executed a background GC, a foreground GC, or a diff --git a/src/gc/sample/CMakeLists.txt b/src/gc/sample/CMakeLists.txt index 5fe7887963..42f097a6e3 100644 --- a/src/gc/sample/CMakeLists.txt +++ b/src/gc/sample/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories(../env) set(SOURCES GCSample.cpp gcenv.ee.cpp + ../gcconfig.cpp ../gccommon.cpp ../gceewks.cpp ../gchandletable.cpp diff --git a/src/gc/sample/gcenv.ee.cpp b/src/gc/sample/gcenv.ee.cpp index fa6efbf2d6..03d960819a 100644 --- a/src/gc/sample/gcenv.ee.cpp +++ b/src/gc/sample/gcenv.ee.cpp @@ -286,64 +286,39 @@ bool GCToEEInterface::EagerFinalized(Object* obj) return false; } -MethodTable* GCToEEInterface::GetFreeObjectMethodTable() +bool GCToEEInterface::GetBooleanConfigValue(const char* key, bool* value) { - return g_pFreeObjectMethodTable; + return false; } -bool IsGCSpecialThread() +bool GCToEEInterface::GetIntConfigValue(const char* key, int64_t* value) { - // TODO: Implement for background GC return false; } -bool IsGCThread() +bool GCToEEInterface::GetStringConfigValue(const char* key, const char** value) { return false; } -void SwitchToWriteWatchBarrier() +void GCToEEInterface::FreeStringConfigValue(const char *value) { -} -void SwitchToNonWriteWatchBarrier() -{ } -void LogSpewAlways(const char * /*fmt*/, ...) +MethodTable* GCToEEInterface::GetFreeObjectMethodTable() { + return g_pFreeObjectMethodTable; } -uint32_t CLRConfig::GetConfigValue(ConfigDWORDInfo eType) +bool IsGCSpecialThread() { - switch (eType) - { - case UNSUPPORTED_BGCSpinCount: - return 140; - - case UNSUPPORTED_BGCSpin: - return 2; - - case UNSUPPORTED_GCLogEnabled: - case UNSUPPORTED_GCLogFile: - case UNSUPPORTED_GCLogFileSize: - case EXTERNAL_GCStressStart: - case INTERNAL_GCStressStartAtJit: - case INTERNAL_DbgDACSkipVerifyDlls: - return 0; - - case Config_COUNT: - default: -#ifdef _MSC_VER -#pragma warning(suppress:4127) // Constant conditional expression in ASSERT below -#endif - ASSERT(!"Unknown config value type"); - return 0; - } + // TODO: Implement for background GC + return false; } -HRESULT CLRConfig::GetConfigValue(ConfigStringInfo /*eType*/, TCHAR * * outVal) +bool IsGCThread() { - *outVal = NULL; - return 0; + return false; } + diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h index 81e9fae052..8a21a9d8fd 100644 --- a/src/inc/clrconfigvalues.h +++ b/src/inc/clrconfigvalues.h @@ -325,7 +325,6 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCLogFileSize, W("GCLogFileSize"), 0, "Spec RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCCompactRatio, W("GCCompactRatio"), 0, "Specifies the ratio compacting GCs vs sweeping ") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_GCPollType, W("GCPollType"), "") RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_NewGCCalc, W("NewGCCalc"), "", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCprnLvl, W("GCprnLvl"), "Specifies the maximum level of GC logging") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCRetainVM, W("GCRetainVM"), 0, "When set we put the segments that should be deleted on a standby list (instead of releasing them back to the OS) which will be considered to satisfy new segment requests (note that the same thing can be specified via API which is the supported way)") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCSegmentSize, W("GCSegmentSize"), "Specifies the managed heap segment size") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCLOHCompact, W("GCLOHCompact"), "Specifies the LOH compaction mode") @@ -334,9 +333,6 @@ RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_GCStress, W("GCStress"), 0, "trigger GCs at CONFIG_DWORD_INFO_EX(INTERNAL_GcStressOnDirectCalls, W("GcStressOnDirectCalls"), 0, "whether to trigger a GC on direct calls", CLRConfig::REGUTIL_default) RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCStressStart, W("GCStressStart"), 0, "start GCStress after N stress GCs have been attempted") RETAIL_CONFIG_DWORD_INFO(INTERNAL_GCStressStartAtJit, W("GCStressStartAtJit"), 0, "start GCStress after N items are jitted") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCtraceEnd, W("GCtraceEnd"), "Specifies the index of the GC when the logging should end") -CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_GCtraceFacility, W("GCtraceFacility"), "Specifies where to log to (this allows you to log to console, the stress log or a normal CLR log (good when you need to correlate the GC activities with other CLR activities)") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCtraceStart, W("GCtraceStart"), "Specifies the index of the GC when the logging should start") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_gcTrimCommitOnLowMemory, W("gcTrimCommitOnLowMemory"), "When set we trim the committed space more aggressively for the ephemeral seg. This is used for running many instances of server processes where they want to keep as little memory committed as possible") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_BGCSpinCount, W("BGCSpinCount"), 140, "Specifies the bgc spin count") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_BGCSpin, W("BGCSpin"), 2, "Specifies the bgc spin time") diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index 60e7ea4c59..4e6a523ba2 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -122,6 +122,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON ) set( GC_SOURCES_DAC_AND_WKS_COMMON + ../gc/gcconfig.cpp ../gc/gccommon.cpp ../gc/gcscan.cpp ../gc/gcsvr.cpp diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp index 617b022516..ec16bdd153 100644 --- a/src/vm/ceemain.cpp +++ b/src/vm/ceemain.cpp @@ -478,8 +478,8 @@ void InitializeStartupFlags() g_IGCconcurrent = 0; - InitializeHeapType((flags & STARTUP_SERVER_GC) != 0); g_heap_type = (flags & STARTUP_SERVER_GC) == 0 ? GC_HEAP_WKS : GC_HEAP_SVR; + g_IGCHoardVM = (flags & STARTUP_HOARD_GC_VM) == 0 ? 0 : 1; } #endif // CROSSGEN_COMPILE diff --git a/src/vm/eeconfig.cpp b/src/vm/eeconfig.cpp index 2ec6d39cdd..05cdd0aa6c 100644 --- a/src/vm/eeconfig.cpp +++ b/src/vm/eeconfig.cpp @@ -178,14 +178,6 @@ HRESULT EEConfig::Init() iGCHeapVerify = 0; // Heap Verification OFF by default #endif -#ifdef _DEBUG // TRACE_GC - iGCtraceStart = INT_MAX; // Set to huge value so GCtrace is off by default - iGCtraceEnd = INT_MAX; - iGCtraceFac = 0; - iGCprnLvl = DEFAULT_GC_PRN_LVL; - -#endif - #if defined(STRESS_HEAP) || defined(_DEBUG) iGCStress = 0; #endif diff --git a/src/vm/eeconfig.h b/src/vm/eeconfig.h index 1ec4460fd8..a12a94c73e 100644 --- a/src/vm/eeconfig.h +++ b/src/vm/eeconfig.h @@ -616,15 +616,6 @@ public: GCStressFlags GetGCStressLevel() const { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return GCStressFlags(iGCStress); } #endif -#ifdef _DEBUG // TRACE_GC - - int GetGCtraceStart() const {LIMITED_METHOD_CONTRACT; return iGCtraceStart; } - int GetGCtraceEnd () const {LIMITED_METHOD_CONTRACT; return iGCtraceEnd; } - int GetGCtraceFac () const {LIMITED_METHOD_CONTRACT; return iGCtraceFac; } - int GetGCprnLvl () const {LIMITED_METHOD_CONTRACT; return iGCprnLvl; } - -#endif - #ifdef STRESS_HEAP bool IsGCStressMix () const {LIMITED_METHOD_CONTRACT; return iGCStressMix != 0;} @@ -977,15 +968,6 @@ private: //---------------------------------------------------------------- int iGCHeapVerify; #endif -#ifdef _DEBUG // TRACE_GC - - int iGCtraceStart; - int iGCtraceEnd; - int iGCtraceFac; - int iGCprnLvl; - -#endif - #if defined(STRESS_HEAP) || defined(_DEBUG) int iGCStress; #endif diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp index 8be0b29d58..38c8ef0340 100644 --- a/src/vm/gcenv.ee.cpp +++ b/src/vm/gcenv.ee.cpp @@ -993,3 +993,125 @@ MethodTable* GCToEEInterface::GetFreeObjectMethodTable() assert(g_pFreeObjectMethodTable != nullptr); return g_pFreeObjectMethodTable; } + +// These are arbitrary, we shouldn't ever be having confrig keys or values +// longer than these lengths. +const size_t MaxConfigKeyLength = 255; +const size_t MaxConfigValueLength = 255; + +bool GCToEEInterface::GetBooleanConfigValue(const char* key, bool* value) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + // these configuration values are given to us via startup flags. + if (strcmp(key, "gcServer") == 0) + { + *value = g_heap_type == GC_HEAP_SVR; + return true; + } + + if (strcmp(key, "gcConcurrent") == 0) + { + *value = g_IGCconcurrent != 0; + return true; + } + + if (strcmp(key, "GCRetainVM") == 0) + { + *value = !!g_pConfig->GetGCRetainVM(); + return true; + } + + WCHAR configKey[MaxConfigKeyLength]; + if (MultiByteToWideChar(CP_ACP, 0, key, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) + { + // whatever this is... it's not something we care about. (It was too long, wasn't unicode, etc.) + return false; + } + + // otherwise, ask the config subsystem. + if (CLRConfig::IsConfigOptionSpecified(configKey)) + { + CLRConfig::ConfigDWORDInfo info { configKey , 0, CLRConfig::EEConfig_default }; + *value = CLRConfig::GetConfigValue(info) != 0; + return true; + } + + return false; +} + +bool GCToEEInterface::GetIntConfigValue(const char* key, int64_t* value) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + WCHAR configKey[MaxConfigKeyLength]; + if (MultiByteToWideChar(CP_ACP, 0, key, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) + { + // whatever this is... it's not something we care about. (It was too long, wasn't unicode, etc.) + return false; + } + + if (CLRConfig::IsConfigOptionSpecified(configKey)) + { + CLRConfig::ConfigDWORDInfo info { configKey , 0, CLRConfig::EEConfig_default }; + *value = CLRConfig::GetConfigValue(info); + return true; + } + + return false; +} + +bool GCToEEInterface::GetStringConfigValue(const char* key, const char** value) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + + WCHAR configKey[MaxConfigKeyLength]; + if (MultiByteToWideChar(CP_ACP, 0, key, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) + { + // whatever this is... it's not something we care about. (It was too long, wasn't unicode, etc.) + return false; + } + + CLRConfig::ConfigStringInfo info { configKey, CLRConfig::EEConfig_default }; + LPWSTR out = CLRConfig::GetConfigValue(info); + if (!out) + { + // config not found + return false; + } + + // not allocated on the stack since it escapes this function + AStringHolder configResult = new (nothrow) char[MaxConfigValueLength]; + if (!configResult) + { + CLRConfig::FreeConfigString(out); + return false; + } + + if (WideCharToMultiByte(CP_ACP, 0, out, -1 /* out is null-terminated */, + configResult.GetValue(), MaxConfigKeyLength, nullptr, nullptr) == 0) + { + // this should only happen if the config subsystem gives us a string that's not valid + // unicode. + CLRConfig::FreeConfigString(out); + return false; + } + + *value = configResult.Extract(); + CLRConfig::FreeConfigString(out); + return true; +} + +void GCToEEInterface::FreeStringConfigValue(const char* value) +{ + delete [] value; +} diff --git a/src/vm/gcenv.ee.h b/src/vm/gcenv.ee.h index 6c917a5a2b..6b02f5cfa1 100644 --- a/src/vm/gcenv.ee.h +++ b/src/vm/gcenv.ee.h @@ -52,6 +52,10 @@ public: bool ForceFullGCToBeBlocking(); bool EagerFinalized(Object* obj); MethodTable* GetFreeObjectMethodTable(); + bool GetBooleanConfigValue(const char* key, bool* value); + bool GetIntConfigValue(const char* key, int64_t* value); + bool GetStringConfigValue(const char* key, const char** value); + void FreeStringConfigValue(const char* value); }; } // namespace standalone |