summaryrefslogtreecommitdiff
path: root/src/gc/gc.cpp
diff options
context:
space:
mode:
authorJack Pappas <jack-pappas@users.noreply.github.com>2018-11-06 18:07:47 -0500
committerMaoni Stephens <Maoni0@users.noreply.github.com>2018-11-06 15:07:47 -0800
commit2bf55bc5ca8b09dd26e32a9ee259ab22fb69806b (patch)
tree3cfd121c1504997f9cfff765310910f7a020d8e9 /src/gc/gc.cpp
parent8826f6f8c07c325046b78f28c57b24b201e487d2 (diff)
downloadcoreclr-2bf55bc5ca8b09dd26e32a9ee259ab22fb69806b.tar.gz
coreclr-2bf55bc5ca8b09dd26e32a9ee259ab22fb69806b.tar.bz2
coreclr-2bf55bc5ca8b09dd26e32a9ee259ab22fb69806b.zip
Loop-free GC rounding helpers with _BitScanReverse. (#20157)
Diffstat (limited to 'src/gc/gc.cpp')
-rw-r--r--src/gc/gc.cpp119
1 files changed, 55 insertions, 64 deletions
diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp
index c5c178b943..a8a47c7788 100644
--- a/src/gc/gc.cpp
+++ b/src/gc/gc.cpp
@@ -308,78 +308,69 @@ void GCStatistics::DisplayAndUpdate()
#endif // GC_STATS
-#ifdef BIT64
-#define TOTAL_TIMES_TO_SHIFT 6
-#else
-#define TOTAL_TIMES_TO_SHIFT 5
-#endif // BIT64
-
+inline
size_t round_up_power2 (size_t size)
{
- unsigned short shift = 1;
- size_t shifted = 0;
-
- size--;
- for (unsigned short i = 0; i < TOTAL_TIMES_TO_SHIFT; i++)
- {
- shifted = size | (size >> shift);
- if (shifted == size)
- {
- break;
- }
-
- size = shifted;
- shift <<= 1;
- }
- shifted++;
+ // Get the 0-based index of the most-significant bit in size-1.
+ // If the call failed (because size-1 is zero), size must be 1,
+ // so return 1 (because 1 rounds up to itself).
+ DWORD highest_set_bit_index;
+ if (0 ==
+#ifdef BIT64
+ BitScanReverse64(
+#else
+ BitScanReverse(
+#endif
+ &highest_set_bit_index, size - 1)) { return 1; }
- return shifted;
+ // The size == 0 case (which would have overflowed to SIZE_MAX when decremented)
+ // is handled below by relying on the fact that highest_set_bit_index is the maximum value
+ // (31 or 63, depending on sizeof(size_t)) and left-shifting a value >= 2 by that
+ // number of bits shifts in zeros from the right, resulting in an output of zero.
+ return static_cast<size_t>(2) << highest_set_bit_index;
}
inline
size_t round_down_power2 (size_t size)
{
- size_t power2 = round_up_power2 (size);
-
- if (power2 != size)
- {
- power2 >>= 1;
- }
+ // Get the 0-based index of the most-significant bit in size.
+ // If the call failed, size must be zero so return zero.
+ DWORD highest_set_bit_index;
+ if (0 ==
+#ifdef BIT64
+ BitScanReverse64(
+#else
+ BitScanReverse(
+#endif
+ &highest_set_bit_index, size)) { return 0; }
- return power2;
+ // Left-shift 1 by highest_set_bit_index to get back a value containing only
+ // the most-significant set bit of size, i.e. size rounded down
+ // to the next power-of-two value.
+ return static_cast<size_t>(1) << highest_set_bit_index;
}
-// the index starts from 0.
-int index_of_set_bit (size_t power2)
+// Get the 0-based index of the most-significant bit in the value.
+// Returns -1 if the input value is zero (i.e. has no set bits).
+inline
+int index_of_highest_set_bit (size_t value)
{
- int low = 0;
- int high = sizeof (size_t) * 8 - 1;
- int mid;
- while (low <= high)
- {
- mid = ((low + high)/2);
- size_t temp = (size_t)1 << mid;
- if (power2 & temp)
- {
- return mid;
- }
- else if (power2 < temp)
- {
- high = mid - 1;
- }
- else
- {
- low = mid + 1;
- }
- }
-
- return -1;
+ // Get the 0-based index of the most-significant bit in the value.
+ // If the call failed (because value is zero), return -1.
+ DWORD highest_set_bit_index;
+ return (0 ==
+#ifdef BIT64
+ BitScanReverse64(
+#else
+ BitScanReverse(
+#endif
+ &highest_set_bit_index, value)) ? -1 : static_cast<int>(highest_set_bit_index);
}
inline
int relative_index_power2_plug (size_t power2)
{
- int index = index_of_set_bit (power2);
+ int index = index_of_highest_set_bit (power2);
assert (index <= MAX_INDEX_POWER2);
return ((index < MIN_INDEX_POWER2) ? 0 : (index - MIN_INDEX_POWER2));
@@ -388,7 +379,7 @@ int relative_index_power2_plug (size_t power2)
inline
int relative_index_power2_free_space (size_t power2)
{
- int index = index_of_set_bit (power2);
+ int index = index_of_highest_set_bit (power2);
assert (index <= MAX_INDEX_POWER2);
return ((index < MIN_INDEX_POWER2) ? -1 : (index - MIN_INDEX_POWER2));
@@ -8688,7 +8679,7 @@ public:
}
}
- int bucket_power2 = index_of_set_bit (round_down_power2 (size));
+ int bucket_power2 = index_of_highest_set_bit (size);
if (bucket_power2 < base_power2)
{
return;
@@ -8791,7 +8782,7 @@ public:
plug_size_to_fit += (pad_in_front ? Align(min_obj_size) : 0);
#endif //SHORT_PLUGS
- int plug_power2 = index_of_set_bit (round_up_power2 (plug_size_to_fit + Align(min_obj_size)));
+ int plug_power2 = index_of_highest_set_bit (round_up_power2 (plug_size_to_fit + Align(min_obj_size)));
ptrdiff_t i;
uint8_t* new_address = 0;
@@ -8873,9 +8864,9 @@ retry:
(plug_size - pad),
pad,
pinned_plug (m),
- index_of_set_bit (round_down_power2 (free_space_size)),
+ index_of_highest_set_bit (free_space_size),
(pinned_plug (m) - pinned_len (m)),
- index_of_set_bit (round_down_power2 (new_free_space_size))));
+ index_of_highest_set_bit (new_free_space_size)));
#endif //SIMPLE_DPRINTF
#ifdef SHORT_PLUGS
@@ -8919,9 +8910,9 @@ retry:
old_loc,
new_address,
(plug_size - pad),
- index_of_set_bit (round_down_power2 (free_space_size)),
+ index_of_highest_set_bit (free_space_size),
heap_segment_plan_allocated (seg),
- index_of_set_bit (round_down_power2 (new_free_space_size))));
+ index_of_highest_set_bit (new_free_space_size)));
#endif //SIMPLE_DPRINTF
if (realign_padding_p)
@@ -8953,7 +8944,7 @@ retry:
(!chosen_power2) && (i < free_space_count));
}
- int new_bucket_power2 = index_of_set_bit (round_down_power2 (new_free_space_size));
+ int new_bucket_power2 = index_of_highest_set_bit (new_free_space_size);
if (new_bucket_power2 < base_power2)
{
@@ -33465,7 +33456,7 @@ HRESULT GCHeap::Initialize ()
gc_heap::min_loh_segment_size = large_seg_size;
gc_heap::min_segment_size = min (seg_size, large_seg_size);
#ifdef SEG_MAPPING_TABLE
- gc_heap::min_segment_size_shr = index_of_set_bit (gc_heap::min_segment_size);
+ gc_heap::min_segment_size_shr = index_of_highest_set_bit (gc_heap::min_segment_size);
#endif //SEG_MAPPING_TABLE
#ifdef MULTIPLE_HEAPS