1 /*
  2  * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "precompiled.hpp"
 26 #include "gc/shenandoah/shenandoahSimpleBitMap.inline.hpp"
 27 
 28 ShenandoahSimpleBitMap::ShenandoahSimpleBitMap(size_t num_bits) :
 29     _num_bits(num_bits),
 30     _num_words(align_up(num_bits, BitsPerWord) / BitsPerWord),
 31     _bitmap(NEW_C_HEAP_ARRAY(uintx, _num_words, mtGC))
 32 {
 33   clear_all();
 34 }
 35 
 36 ShenandoahSimpleBitMap::~ShenandoahSimpleBitMap() {
 37   if (_bitmap != nullptr) {
 38     FREE_C_HEAP_ARRAY(uintx, _bitmap);
 39   }
 40 }
 41 
 42 size_t ShenandoahSimpleBitMap::count_leading_ones(idx_t start_idx) const {
 43   assert((start_idx >= 0) && (start_idx < _num_bits), "precondition");
 44   size_t array_idx = start_idx >> LogBitsPerWord;
 45   uintx element_bits = _bitmap[array_idx];
 46   uintx bit_number = start_idx & (BitsPerWord - 1);
 47   uintx mask = ~tail_mask(bit_number);
 48   size_t counted_ones = 0;
 49   while ((element_bits & mask) == mask) {
 50     // All bits numbered >= bit_number are set
 51     size_t found_ones = BitsPerWord - bit_number;
 52     counted_ones += found_ones;
 53     // Dead code: do not need to compute: start_idx += found_ones;
 54     // Strength reduction:                array_idx = (start_idx >> LogBitsPerWord)
 55     array_idx++;
 56     element_bits = _bitmap[array_idx];
 57     // Constant folding:                  bit_number = start_idx & (BitsPerWord - 1);
 58     bit_number = 0;
 59     // Constant folding:                  mask = ~right_n_bits(bit_number);
 60     mask = ~0;
 61   }
 62 
 63   // Add in number of consecutive ones starting with the_bit and including more significant bits and return result
 64   uintx aligned = element_bits >> bit_number;
 65   uintx complement = ~aligned;
 66   return counted_ones + count_trailing_zeros<uintx>(complement);
 67 }
 68 
 69 size_t ShenandoahSimpleBitMap::count_trailing_ones(idx_t last_idx) const {
 70   assert((last_idx >= 0) && (last_idx < _num_bits), "precondition");
 71   size_t array_idx = last_idx >> LogBitsPerWord;
 72   uintx element_bits = _bitmap[array_idx];
 73   uintx bit_number = last_idx & (BitsPerWord - 1);
 74   // All ones from bit 0 to the_bit
 75   uintx mask = tail_mask(bit_number + 1);
 76   size_t counted_ones = 0;
 77   while ((element_bits & mask) == mask) {
 78     // All bits numbered <= bit_number are set
 79     size_t found_ones = bit_number + 1;
 80     counted_ones += found_ones;
 81     // Dead code: do not need to compute: last_idx -= found_ones;
 82     array_idx--;
 83     element_bits = _bitmap[array_idx];
 84     // Constant folding:                  bit_number = last_idx & (BitsPerWord - 1);
 85     bit_number = BitsPerWord - 1;
 86     // Constant folding:                  mask = right_n_bits(bit_number + 1);
 87     mask = ~0;
 88   }
 89 
 90   // Add in number of consecutive ones starting with the_bit and including less significant bits and return result
 91   uintx aligned = element_bits << (BitsPerWord - (bit_number + 1));
 92   uintx complement = ~aligned;
 93   return counted_ones + count_leading_zeros<uintx>(complement);
 94 }
 95 
 96 bool ShenandoahSimpleBitMap::is_forward_consecutive_ones(idx_t start_idx, idx_t count) const {
 97   while (count > 0) {
 98     assert((start_idx >= 0) && (start_idx < _num_bits), "precondition: start_idx: " SSIZE_FORMAT ", count: " SSIZE_FORMAT,
 99            start_idx, count);
100     assert(start_idx + count <= (idx_t) _num_bits, "precondition");
101     size_t array_idx = start_idx >> LogBitsPerWord;
102     uintx bit_number = start_idx & (BitsPerWord - 1);
103     uintx element_bits = _bitmap[array_idx];
104     uintx bits_to_examine  = BitsPerWord - bit_number;
105     element_bits >>= bit_number;
106     uintx complement = ~element_bits;
107     uintx trailing_ones;
108     if (complement != 0) {
109       trailing_ones = count_trailing_zeros<uintx>(complement);
110     } else {
111       trailing_ones = bits_to_examine;
112     }
113     if (trailing_ones >= (uintx) count) {
114       return true;
115     } else if (trailing_ones == bits_to_examine) {
116       start_idx += bits_to_examine;
117       count -= bits_to_examine;
118       // Repeat search with smaller goal
119     } else {
120       return false;
121     }
122   }
123   return true;
124 }
125 
126 bool ShenandoahSimpleBitMap::is_backward_consecutive_ones(idx_t last_idx, idx_t count) const {
127   while (count > 0) {
128     assert((last_idx >= 0) && (last_idx < _num_bits), "precondition");
129     assert(last_idx - count >= -1, "precondition");
130     size_t array_idx = last_idx >> LogBitsPerWord;
131     uintx bit_number = last_idx & (BitsPerWord - 1);
132     uintx element_bits = _bitmap[array_idx];
133     uintx bits_to_examine = bit_number + 1;
134     element_bits <<= (BitsPerWord - bits_to_examine);
135     uintx complement = ~element_bits;
136     uintx leading_ones;
137     if (complement != 0) {
138       leading_ones = count_leading_zeros<uintx>(complement);
139     } else {
140       leading_ones = bits_to_examine;
141     }
142     if (leading_ones >= (uintx) count) {
143       return true;
144     } else if (leading_ones == bits_to_examine) {
145       last_idx -= leading_ones;
146       count -= leading_ones;
147       // Repeat search with smaller goal
148     } else {
149       return false;
150     }
151   }
152   return true;
153 }
154 
155 idx_t ShenandoahSimpleBitMap::find_first_consecutive_set_bits(idx_t beg, idx_t end, size_t num_bits) const {
156   assert((beg >= 0) && (beg < _num_bits), "precondition");
157 
158   // Stop looking if there are not num_bits remaining in probe space.
159   idx_t start_boundary = end - num_bits;
160   if (beg > start_boundary) {
161     return end;
162   }
163   uintx array_idx = beg >> LogBitsPerWord;
164   uintx bit_number = beg & (BitsPerWord - 1);
165   uintx element_bits = _bitmap[array_idx];
166   if (bit_number > 0) {
167     uintx mask_out = tail_mask(bit_number);
168     element_bits &= ~mask_out;
169   }
170 
171   // The following loop minimizes the number of spans probed in order to find num_bits consecutive bits.
172   // For example, if bit_number = beg = 0, num_bits = 8, and element bits equals 00111111_11000000_00000000_10011000B,
173   // we need only 3 probes to find the match at bit offset 22.
174   //
175   // Let beg = 0
176   // element_bits = 00111111_11000000_00000000_10011000B;
177   //                                           ________   (the searched span)
178   //                                           ^   ^  ^- bit_number = beg = 0
179   //                                           |   +-- next_start_candidate_1 (where next 1 is found)
180   //                                           +------ next_start_candidate_2 (start of the trailing 1s within span)
181   // Let beg = 7
182   // element_bits = 00111111_11000000_00000000_10011000B;
183   //                          ^       ^_________   (the searched span)
184   //                          |       |        ^- bit_number = beg = 7
185   //                          |       +---------- next_start_candidate_2 (there are no trailing 1s within span)
186   //                          +------------------ next_start_candidate_1 (where next 1 is found)
187   // Let beg = 22
188   // Let beg = 22
189   // element_bits = 00111111_11000001_11111100_10011000B;
190   //                  _________   (the searched span)
191   //                          ^- bit_number = beg = 18
192   // Here, is_forward_consecutive_ones(22, 8) succeeds and we report the match
193 
194   while (true) {
195     if (element_bits == 0) {
196       // move to the next element
197       beg += BitsPerWord - bit_number;
198       if (beg > start_boundary) {
199         // No match found.
200         return end;
201       }
202       array_idx++;
203       bit_number = 0;
204       element_bits = _bitmap[array_idx];
205     } else if (is_forward_consecutive_ones(beg, num_bits)) {
206       return beg;
207     } else {
208       // There is at least one non-zero bit within the masked element_bits. Arrange to skip over bits that
209       // cannot be part of a consecutive-ones match.
210       uintx next_set_bit = count_trailing_zeros<uintx>(element_bits);
211       uintx next_start_candidate_1 = (array_idx << LogBitsPerWord) + next_set_bit;
212 
213       // There is at least one zero bit in this span. Align the next probe at the start of trailing ones for probed span,
214       // or align at end of span if this span has no trailing ones.
215       size_t trailing_ones = count_trailing_ones(beg + num_bits - 1);
216       uintx next_start_candidate_2 = beg + num_bits - trailing_ones;
217 
218       beg = MAX2(next_start_candidate_1, next_start_candidate_2);
219       if (beg > start_boundary) {
220         // No match found.
221         return end;
222       }
223       array_idx = beg >> LogBitsPerWord;
224       element_bits = _bitmap[array_idx];
225       bit_number = beg & (BitsPerWord - 1);
226       if (bit_number > 0) {
227         size_t mask_out = tail_mask(bit_number);
228         element_bits &= ~mask_out;
229       }
230     }
231   }
232 }
233 
234 idx_t ShenandoahSimpleBitMap::find_last_consecutive_set_bits(const idx_t beg, idx_t end, const size_t num_bits) const {
235 
236   assert((end >= 0) && (end < _num_bits), "precondition");
237 
238   // Stop looking if there are not num_bits remaining in probe space.
239   idx_t last_boundary = beg + num_bits;
240   if (end < last_boundary) {
241     return beg;
242   }
243 
244   size_t array_idx = end >> LogBitsPerWord;
245   uintx bit_number = end & (BitsPerWord - 1);
246   uintx element_bits = _bitmap[array_idx];
247   if (bit_number < BitsPerWord - 1) {
248     uintx mask_in = tail_mask(bit_number + 1);
249     element_bits &= mask_in;
250   }
251 
252   // See comment in find_first_consecutive_set_bits to understand how this loop works.
253   while (true) {
254     if (element_bits == 0) {
255       // move to the previous element
256       end -= bit_number + 1;
257       if (end < last_boundary) {
258         // No match found.
259         return beg;
260       }
261       array_idx--;
262       bit_number = BitsPerWord - 1;
263       element_bits = _bitmap[array_idx];
264     } else if (is_backward_consecutive_ones(end, num_bits)) {
265       return end + 1 - num_bits;
266     } else {
267       // There is at least one non-zero bit within the masked element_bits. Arrange to skip over bits that
268       // cannot be part of a consecutive-ones match.
269       uintx next_set_bit = BitsPerWord - (1 + count_leading_zeros<uintx>(element_bits));
270       uintx next_last_candidate_1 = (array_idx << LogBitsPerWord) + next_set_bit;
271 
272       // There is at least one zero bit in this span.  Align the next probe at the end of leading ones for probed span,
273       // or align before start of span if this span has no leading ones.
274       size_t leading_ones = count_leading_ones(end - (num_bits - 1));
275       uintx next_last_candidate_2 = end - (num_bits - leading_ones);
276 
277       end = MIN2(next_last_candidate_1, next_last_candidate_2);
278       if (end < last_boundary) {
279         // No match found.
280         return beg;
281       }
282       array_idx = end >> LogBitsPerWord;
283       bit_number = end & (BitsPerWord - 1);
284       element_bits = _bitmap[array_idx];
285       if (bit_number < BitsPerWord - 1){
286         size_t mask_in = tail_mask(bit_number + 1);
287         element_bits &= mask_in;
288       }
289     }
290   }
291 }