Skip to content

Commit 8531fa1

Browse files
kdnilsenY. Srinivas Ramakrishna
andcommitted
8358735: GenShen: block_start() may be incorrect after class unloading
Co-authored-by: Y. Srinivas Ramakrishna <[email protected]> Reviewed-by: wkemper
1 parent c6a8027 commit 8531fa1

12 files changed

+883
-42
lines changed

src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ class ShenandoahHeap : public CollectedHeap {
270270
public:
271271

272272
inline HeapWord* base() const { return _heap_region.start(); }
273+
inline HeapWord* end() const { return _heap_region.end(); }
273274

274275
inline size_t num_regions() const { return _num_regions; }
275276
inline bool is_heap_region_special() { return _heap_region_special; }

src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,26 @@ bool ShenandoahMarkBitMap::is_bitmap_clear_range(const HeapWord* start, const He
5757
return (result == end);
5858
}
5959

60+
HeapWord* ShenandoahMarkBitMap::get_prev_marked_addr(const HeapWord* limit,
61+
const HeapWord* addr) const {
62+
#ifdef ASSERT
63+
ShenandoahHeap* heap = ShenandoahHeap::heap();
64+
ShenandoahHeapRegion* r = heap->heap_region_containing(addr);
65+
ShenandoahMarkingContext* ctx = heap->marking_context();
66+
HeapWord* tams = ctx->top_at_mark_start(r);
67+
assert(limit != nullptr, "limit must not be null");
68+
assert(limit >= r->bottom(), "limit must be more than bottom");
69+
assert(addr <= tams, "addr must be less than TAMS");
70+
#endif
71+
72+
// Round addr down to a possible object boundary to be safe.
73+
size_t const addr_offset = address_to_index(align_down(addr, HeapWordSize << LogMinObjAlignment));
74+
size_t const limit_offset = address_to_index(limit);
75+
size_t const last_offset = get_prev_one_offset(limit_offset, addr_offset);
76+
77+
// cast required to remove const-ness of the value pointed to. We won't modify that object, but my caller might.
78+
return (last_offset > addr_offset)? (HeapWord*) addr + 1: index_to_address(last_offset);
79+
}
6080

6181
HeapWord* ShenandoahMarkBitMap::get_next_marked_addr(const HeapWord* addr,
6282
const HeapWord* limit) const {

src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.hpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,21 @@ class ShenandoahMarkBitMap {
119119
template<bm_word_t flip, bool aligned_right>
120120
inline idx_t get_next_bit_impl(idx_t l_index, idx_t r_index) const;
121121

122-
inline idx_t get_next_one_offset (idx_t l_index, idx_t r_index) const;
122+
// Helper for get_prev_{zero,one}_bit variants.
123+
// - flip designates whether searching for 1s or 0s. Must be one of
124+
// find_{zeros,ones}_flip.
125+
// - aligned_left is true if l_index is a priori on a bm_word_t boundary.
126+
template<bm_word_t flip, bool aligned_left>
127+
inline idx_t get_prev_bit_impl(idx_t l_index, idx_t r_index) const;
128+
129+
// Search for the first marked address in the range [l_index, r_index), or r_index if none found.
130+
inline idx_t get_next_one_offset(idx_t l_index, idx_t r_index) const;
123131

124-
void clear_large_range (idx_t beg, idx_t end);
132+
// Search for last one in the range [l_index, r_index). Return r_index if not found.
133+
inline idx_t get_prev_one_offset(idx_t l_index, idx_t r_index) const;
134+
135+
// Clear the strong and weak mark bits for all index positions >= l_index and < r_index.
136+
void clear_large_range(idx_t beg, idx_t end);
125137

126138
// Verify bit is less than size().
127139
void verify_index(idx_t bit) const NOT_DEBUG_RETURN;
@@ -162,12 +174,14 @@ class ShenandoahMarkBitMap {
162174

163175
bool is_bitmap_clear_range(const HeapWord* start, const HeapWord* end) const;
164176

165-
// Return the address corresponding to the next marked bit at or after
166-
// "addr", and before "limit", if "limit" is non-null. If there is no
167-
// such bit, returns "limit" if that is non-null, or else "endWord()".
177+
// Return the first marked address in the range [addr, limit), or limit if none found.
168178
HeapWord* get_next_marked_addr(const HeapWord* addr,
169179
const HeapWord* limit) const;
170180

181+
// Return the last marked address in the range [limit, addr], or addr+1 if none found.
182+
HeapWord* get_prev_marked_addr(const HeapWord* limit,
183+
const HeapWord* addr) const;
184+
171185
bm_word_t inverted_bit_mask_for_range(idx_t beg, idx_t end) const;
172186
void clear_range_within_word (idx_t beg, idx_t end);
173187
void clear_range (idx_t beg, idx_t end);

src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "gc/shenandoah/shenandoahMarkBitMap.hpp"
3030

3131
#include "runtime/atomicAccess.hpp"
32+
#include "utilities/count_leading_zeros.hpp"
3233
#include "utilities/count_trailing_zeros.hpp"
3334

3435
inline size_t ShenandoahMarkBitMap::address_to_index(const HeapWord* addr) const {
@@ -169,10 +170,99 @@ inline ShenandoahMarkBitMap::idx_t ShenandoahMarkBitMap::get_next_bit_impl(idx_t
169170
return r_index;
170171
}
171172

173+
template<ShenandoahMarkBitMap::bm_word_t flip, bool aligned_left>
174+
inline ShenandoahMarkBitMap::idx_t ShenandoahMarkBitMap::get_prev_bit_impl(idx_t l_index, idx_t r_index) const {
175+
STATIC_ASSERT(flip == find_ones_flip || flip == find_zeros_flip);
176+
verify_range(l_index, r_index);
177+
assert(!aligned_left || is_aligned(l_index, BitsPerWord), "l_index not aligned");
178+
179+
// The first word often contains an interesting bit, either due to
180+
// density or because of features of the calling algorithm. So it's
181+
// important to examine that first word with a minimum of fuss,
182+
// minimizing setup time for later words that will be wasted if the
183+
// first word is indeed interesting.
184+
185+
// The benefit from aligned_left being true is relatively small.
186+
// It saves an operation in the setup for the word search loop.
187+
// It also eliminates the range check on the final result.
188+
// However, callers often have a comparison with l_index, and
189+
// inlining often allows the two comparisons to be combined; it is
190+
// important when !aligned_left that return paths either return
191+
// l_index or a value dominating a comparison with l_index.
192+
// aligned_left is still helpful when the caller doesn't have a
193+
// range check because features of the calling algorithm guarantee
194+
// an interesting bit will be present.
195+
196+
if (l_index < r_index) {
197+
// Get the word containing r_index, and shift out the high-order bits (representing objects that come after r_index)
198+
idx_t index = to_words_align_down(r_index);
199+
assert(BitsPerWord - 2 >= bit_in_word(r_index), "sanity");
200+
size_t shift = BitsPerWord - 2 - bit_in_word(r_index);
201+
bm_word_t cword = (map(index) ^ flip) << shift;
202+
// After this shift, the highest order bits correspond to r_index.
203+
204+
// We give special handling if either of the two most significant bits (Weak or Strong) is set. With 64-bit
205+
// words, the mask of interest is 0xc000_0000_0000_0000. Symbolically, this constant is represented by:
206+
const bm_word_t first_object_mask = ((bm_word_t) 0x3) << (BitsPerWord - 2);
207+
if ((cword & first_object_mask) != 0) {
208+
// The first object is similarly often interesting. When it matters
209+
// (density or features of the calling algorithm make it likely
210+
// the first bit is set), going straight to the next clause compares
211+
// poorly with doing this check first; count_leading_zeros can be
212+
// relatively expensive, plus there is the additional range check.
213+
// But when the first bit isn't set, the cost of having tested for
214+
// it is relatively small compared to the rest of the search.
215+
return r_index;
216+
} else if (cword != 0) {
217+
// Note that there are 2 bits corresponding to every index value (Weak and Strong), and every odd index value
218+
// corresponds to the same object as index-1
219+
// Flipped and shifted first word is non-zero. If leading_zeros is 0 or 1, we return r_index (above).
220+
// if leading zeros is 2 or 3, we return (r_index - 1) or (r_index - 2), and so forth
221+
idx_t result = r_index + 1 - count_leading_zeros(cword);
222+
if (aligned_left || (result >= l_index)) return result;
223+
else {
224+
// Sentinel value means no object found within specified range.
225+
return r_index + 2;
226+
}
227+
} else {
228+
// Flipped and shifted first word is zero. Word search through
229+
// aligned up r_index for a non-zero flipped word.
230+
idx_t limit = aligned_left
231+
? to_words_align_down(l_index) // Minuscule savings when aligned.
232+
: to_words_align_up(l_index);
233+
// Unsigned index is always >= unsigned limit if limit equals zero, so test for strictly greater than before decrement.
234+
while (index-- > limit) {
235+
cword = map(index) ^ flip;
236+
if (cword != 0) {
237+
// cword hods bits:
238+
// 0x03 for the object corresponding to index (and index+1) (count_leading_zeros is 62 or 63)
239+
// 0x0c for the object corresponding to index + 2 (and index+3) (count_leading_zeros is 60 or 61)
240+
// and so on.
241+
idx_t result = bit_index(index + 1) - (count_leading_zeros(cword) + 1);
242+
if (aligned_left || (result >= l_index)) return result;
243+
else {
244+
// Sentinel value means no object found within specified range.
245+
return r_index + 2;
246+
}
247+
}
248+
}
249+
// No bits in range; return r_index+2.
250+
return r_index + 2;
251+
}
252+
}
253+
else {
254+
return r_index + 2;
255+
}
256+
}
257+
172258
inline ShenandoahMarkBitMap::idx_t ShenandoahMarkBitMap::get_next_one_offset(idx_t l_offset, idx_t r_offset) const {
173259
return get_next_bit_impl<find_ones_flip, false>(l_offset, r_offset);
174260
}
175261

262+
inline ShenandoahMarkBitMap::idx_t ShenandoahMarkBitMap::get_prev_one_offset(idx_t l_offset, idx_t r_offset) const {
263+
return get_prev_bit_impl<find_ones_flip, false>(l_offset, r_offset);
264+
}
265+
176266
// Returns a bit mask for a range of bits [beg, end) within a single word. Each
177267
// bit in the mask is 0 if the bit is in the range, 1 if not in the range. The
178268
// returned mask can be used directly to clear the range, or inverted to set the

src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,12 @@ class ShenandoahMarkingContext : public CHeapObj<mtGC> {
6767
inline bool is_marked_or_old(oop obj) const;
6868
inline bool is_marked_strong_or_old(oop obj) const;
6969

70+
// Return address of the first marked address in the range [addr,limit), or limit if no marked object found
7071
inline HeapWord* get_next_marked_addr(const HeapWord* addr, const HeapWord* limit) const;
7172

73+
// Return address of the last marked object in range [limit, start], returning start+1 if no marked object found
74+
inline HeapWord* get_prev_marked_addr(const HeapWord* limit, const HeapWord* start) const;
75+
7276
inline bool allocated_after_mark_start(const oop obj) const;
7377
inline bool allocated_after_mark_start(const HeapWord* addr) const;
7478

src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ inline HeapWord* ShenandoahMarkingContext::get_next_marked_addr(const HeapWord*
7272
return _mark_bit_map.get_next_marked_addr(start, limit);
7373
}
7474

75+
inline HeapWord* ShenandoahMarkingContext::get_prev_marked_addr(const HeapWord* limit, const HeapWord* start) const {
76+
return _mark_bit_map.get_prev_marked_addr(limit, start);
77+
}
78+
7579
inline bool ShenandoahMarkingContext::allocated_after_mark_start(oop obj) const {
7680
const HeapWord* addr = cast_from_oop<HeapWord*>(obj);
7781
return allocated_after_mark_start(addr);

0 commit comments

Comments
 (0)