diff options
author | Sean Gillespie <segilles@microsoft.com> | 2017-09-29 08:00:05 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2017-09-29 08:00:05 +0300 |
commit | 1a119b57822d0daf921eee265f701cbe056af306 (patch) | |
tree | 0388f3ffb7bbc86e4b59b2c9ed33e3c60f19e31b | |
parent | 0ed8a8c8dd52be027fe6f174f6ecb3ad4aaacb06 (diff) |
Port CoreCLR#13736 fix to CoreRT (#4627)
-rw-r--r-- | src/Native/gc/gc.cpp | 54 | ||||
-rw-r--r-- | src/System.Private.CoreLib/src/Resources/Strings.resx | 3 | ||||
-rw-r--r-- | src/System.Private.CoreLib/src/System/GC.cs | 35 |
3 files changed, 69 insertions, 23 deletions
diff --git a/src/Native/gc/gc.cpp b/src/Native/gc/gc.cpp index e95ac1f93..1800d84bc 100644 --- a/src/Native/gc/gc.cpp +++ b/src/Native/gc/gc.cpp @@ -15752,40 +15752,66 @@ start_no_gc_region_status gc_heap::prepare_for_no_gc_region (uint64_t total_size save_data_for_no_gc(); settings.pause_mode = pause_no_gc; current_no_gc_region_info.start_status = start_no_gc_success; - - size_t allocation_no_gc_loh = 0; - size_t allocation_no_gc_soh = 0; - size_t size_per_heap = 0; - total_size = (size_t)((float)total_size * 1.05); + uint64_t allocation_no_gc_loh = 0; + uint64_t allocation_no_gc_soh = 0; + assert(total_size != 0); if (loh_size_known) { - loh_size = (size_t)((float)loh_size * 1.05); - allocation_no_gc_loh = (size_t)loh_size; - allocation_no_gc_soh = (size_t)(total_size - loh_size); + assert(loh_size != 0); + assert(loh_size <= total_size); + allocation_no_gc_loh = loh_size; + allocation_no_gc_soh = total_size - loh_size; } else { - allocation_no_gc_soh = (size_t)total_size; - allocation_no_gc_loh = (size_t)total_size; + allocation_no_gc_soh = total_size; + allocation_no_gc_loh = total_size; } size_t soh_segment_size = get_valid_segment_size(); int soh_align_const = get_alignment_constant (TRUE); - size_t max_soh_allocated = (soh_segment_size - OS_PAGE_SIZE - eph_gen_starts_size); + size_t max_soh_allocated = soh_segment_size - OS_PAGE_SIZE - eph_gen_starts_size; + size_t size_per_heap = 0; + const double scale_factor = 1.05; int num_heaps = 1; #ifdef MULTIPLE_HEAPS num_heaps = n_heaps; -#endif //MULTIPLE_HEAPS - size_t total_allowed_soh_allocation = max_soh_allocated * num_heaps; +#endif // MULTIPLE_HEAPS - if (allocation_no_gc_soh > total_allowed_soh_allocation) + uint64_t total_allowed_soh_allocation = max_soh_allocated * num_heaps; + // [LOCALGC TODO] + // In theory, the upper limit here is the physical memory of the machine, not + // SIZE_T_MAX. This is not true today because total_physical_mem can be + // larger than SIZE_T_MAX if running in wow64 on a machine with more than + // 4GB of RAM. Once Local GC code divergence is resolved and code is flowing + // more freely between branches, it would be good to clean this up to use + // total_physical_mem instead of SIZE_T_MAX. + assert(total_allowed_soh_allocation <= SIZE_T_MAX); + uint64_t total_allowed_loh_allocation = SIZE_T_MAX; + uint64_t total_allowed_soh_alloc_scaled = allocation_no_gc_soh > 0 ? static_cast<uint64_t>(total_allowed_soh_allocation / scale_factor) : 0; + uint64_t total_allowed_loh_alloc_scaled = allocation_no_gc_loh > 0 ? static_cast<uint64_t>(total_allowed_loh_allocation / scale_factor) : 0; + + if (allocation_no_gc_soh > total_allowed_soh_alloc_scaled || + allocation_no_gc_loh > total_allowed_loh_alloc_scaled) { status = start_no_gc_too_large; goto done; } + if (allocation_no_gc_soh > 0) + { + allocation_no_gc_soh = static_cast<uint64_t>(allocation_no_gc_soh * scale_factor); + allocation_no_gc_soh = min (allocation_no_gc_soh, total_allowed_soh_alloc_scaled); + } + + if (allocation_no_gc_loh > 0) + { + allocation_no_gc_loh = static_cast<uint64_t>(allocation_no_gc_loh * scale_factor); + allocation_no_gc_loh = min (allocation_no_gc_loh, total_allowed_loh_alloc_scaled); + } + if (disallow_full_blocking) current_no_gc_region_info.minimal_gc_p = TRUE; diff --git a/src/System.Private.CoreLib/src/Resources/Strings.resx b/src/System.Private.CoreLib/src/Resources/Strings.resx index e3827350b..9d57c995b 100644 --- a/src/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/System.Private.CoreLib/src/Resources/Strings.resx @@ -939,6 +939,9 @@ <data name="ArgumentOutOfRange_NegativeLength" xml:space="preserve"> <value>Length cannot be less than zero.</value> </data> + <data name="ArgumentOutOfRange_NoGCLohSizeGreaterTotalSize" xml:space="preserve"> + <value>lohSize can't be greater than totalSize</value> + </data> <data name="ArgumentOutOfRange_OffsetLength" xml:space="preserve"> <value>Offset and length must refer to a position in the string.</value> </data> diff --git a/src/System.Private.CoreLib/src/System/GC.cs b/src/System.Private.CoreLib/src/System/GC.cs index 5e350b028..b6b7b09a1 100644 --- a/src/System.Private.CoreLib/src/System/GC.cs +++ b/src/System.Private.CoreLib/src/System/GC.cs @@ -324,24 +324,41 @@ namespace System private static bool StartNoGCRegionWorker(long totalSize, bool hasLohSize, long lohSize, bool disallowFullBlockingGC) { - StartNoGCRegionStatus status = - (StartNoGCRegionStatus)RuntimeImports.RhStartNoGCRegion(totalSize, hasLohSize, lohSize, disallowFullBlockingGC); - if (status == StartNoGCRegionStatus.AmountTooLarge) + if (totalSize <= 0) { throw new ArgumentOutOfRangeException( nameof(totalSize), - SR.ArgumentOutOfRangeException_NoGCRegionSizeTooLarge); + SR.Format(SR.ArgumentOutOfRange_MustBePositive, nameof(totalSize))); } - else if (status == StartNoGCRegionStatus.AlreadyInProgress) + + if (hasLohSize) { - throw new InvalidOperationException( - SR.InvalidOperationException_AlreadyInNoGCRegion); + if (lohSize <= 0) + { + throw new ArgumentOutOfRangeException( + nameof(lohSize), + SR.Format(SR.ArgumentOutOfRange_MustBePositive, nameof(lohSize))); + } + + if (lohSize > totalSize) + { + throw new ArgumentOutOfRangeException(nameof(lohSize), SR.ArgumentOutOfRange_NoGCLohSizeGreaterTotalSize); + } } - else if (status == StartNoGCRegionStatus.NotEnoughMemory) + + StartNoGCRegionStatus status = + (StartNoGCRegionStatus)RuntimeImports.RhStartNoGCRegion(totalSize, hasLohSize, lohSize, disallowFullBlockingGC); + switch (status) { - return false; + case StartNoGCRegionStatus.NotEnoughMemory: + return false; + case StartNoGCRegionStatus.AlreadyInProgress: + throw new InvalidOperationException(SR.InvalidOperationException_AlreadyInNoGCRegion); + case StartNoGCRegionStatus.AmountTooLarge: + throw new ArgumentOutOfRangeException(nameof(totalSize), SR.ArgumentOutOfRangeException_NoGCRegionSizeTooLarge); } + Debug.Assert(status == StartNoGCRegionStatus.Succeeded); return true; } |