Skip to content

Commit d376bed

Browse files
author
William Kemper
committedJun 26, 2023
8310680: GenShen: In-place region promotions may fail
Reviewed-by: kdnilsen, ysr
1 parent aa5e40b commit d376bed

File tree

5 files changed

+43
-18
lines changed

5 files changed

+43
-18
lines changed
 

‎src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp

+29-6
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@
4141
#include "runtime/globals_extension.hpp"
4242
#include "utilities/quickSort.hpp"
4343

44+
inline void assert_no_in_place_promotions() {
45+
#ifdef ASSERT
46+
class ShenandoahNoInPlacePromotions : public ShenandoahHeapRegionClosure {
47+
public:
48+
void heap_region_do(ShenandoahHeapRegion *r) override {
49+
assert(r->get_top_before_promote() == nullptr,
50+
"Region " SIZE_FORMAT " should not be ready for in-place promotion", r->index());
51+
}
52+
} cl;
53+
ShenandoahHeap::heap()->heap_region_iterate(&cl);
54+
#endif
55+
}
56+
57+
4458
// sort by decreasing garbage (so most garbage comes first)
4559
int ShenandoahHeuristics::compare_by_garbage(RegionData a, RegionData b) {
4660
if (a._u._garbage > b._u._garbage)
@@ -125,6 +139,10 @@ static int compare_by_aged_live(AgedRegionData a, AgedRegionData b) {
125139
// Returns bytes of old-gen memory consumed by selected aged regions
126140
size_t ShenandoahHeuristics::select_aged_regions(size_t old_available, size_t num_regions,
127141
bool candidate_regions_for_promotion_by_copy[]) {
142+
143+
// There should be no regions configured for subsequent in-place-promotions carried over from the previous cycle.
144+
assert_no_in_place_promotions();
145+
128146
ShenandoahHeap* heap = ShenandoahHeap::heap();
129147
assert(heap->mode()->is_generational(), "Only in generational mode");
130148
ShenandoahMarkingContext* const ctx = heap->marking_context();
@@ -153,22 +171,27 @@ size_t ShenandoahHeuristics::select_aged_regions(size_t old_available, size_t nu
153171
continue;
154172
}
155173
if (r->age() >= InitialTenuringThreshold) {
156-
r->save_top_before_promote();
157174
if ((r->garbage() < old_garbage_threshold)) {
158175
HeapWord* tams = ctx->top_at_mark_start(r);
159176
HeapWord* original_top = r->top();
160177
if (tams == original_top) {
161-
// Fill the remnant memory within this region to assure no allocations prior to promote in place. Otherwise,
162-
// newly allocated objects will not be parseable when promote in place tries to register them. Furthermore, any
163-
// new allocations would not necessarily be eligible for promotion. This addresses both issues.
178+
// No allocations from this region have been made during concurrent mark. It meets all the criteria
179+
// for in-place-promotion. Though we only need the value of top when we fill the end of the region,
180+
// we use this field to indicate that this region should be promoted in place during the evacuation
181+
// phase.
182+
r->save_top_before_promote();
183+
164184
size_t remnant_size = r->free() / HeapWordSize;
165185
if (remnant_size > ShenandoahHeap::min_fill_size()) {
166186
ShenandoahHeap::fill_with_object(original_top, remnant_size);
187+
// Fill the remnant memory within this region to assure no allocations prior to promote in place. Otherwise,
188+
// newly allocated objects will not be parseable when promote in place tries to register them. Furthermore, any
189+
// new allocations would not necessarily be eligible for promotion. This addresses both issues.
167190
r->set_top(r->end());
168191
promote_in_place_pad += remnant_size * HeapWordSize;
169192
} else {
170193
// Since the remnant is so small that it cannot be filled, we don't have to worry about any accidental
171-
// allocations occuring within this region before the region is promoted in place.
194+
// allocations occurring within this region before the region is promoted in place.
172195
}
173196
promote_in_place_regions++;
174197
promote_in_place_live += r->get_live_data_bytes();
@@ -319,7 +342,7 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec
319342
// ShenandoahOldGarbageThreshold so it will be promoted in place, or because there is not sufficient room
320343
// in old gen to hold the evacuated copies of this region's live data. In both cases, we choose not to
321344
// place this region into the collection set.
322-
if (region->garbage_before_padded_for_promote() < old_garbage_threshold) {
345+
if (region->get_top_before_promote() != nullptr) {
323346
regular_regions_promoted_in_place++;
324347
regular_regions_promoted_usage += region->used_before_promote();
325348
}

‎src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -1271,9 +1271,11 @@ void ShenandoahConcurrentGC::op_final_updaterefs() {
12711271

12721272
void ShenandoahConcurrentGC::op_final_roots() {
12731273

1274-
ShenandoahHeap* heap = ShenandoahHeap::heap();
1275-
if (heap->is_aging_cycle()) {
1276-
ShenandoahMarkingContext* ctx = heap->complete_marking_context();
1274+
ShenandoahHeap *heap = ShenandoahHeap::heap();
1275+
heap->set_concurrent_weak_root_in_progress(false);
1276+
1277+
if (heap->mode()->is_generational()) {
1278+
ShenandoahMarkingContext *ctx = heap->complete_marking_context();
12771279

12781280
for (size_t i = 0; i < heap->num_regions(); i++) {
12791281
ShenandoahHeapRegion *r = heap->get_region(i);
@@ -1282,14 +1284,12 @@ void ShenandoahConcurrentGC::op_final_roots() {
12821284
HeapWord* top = r->top();
12831285
if (top > tams) {
12841286
r->reset_age();
1285-
} else {
1287+
} else if (heap->is_aging_cycle()) {
12861288
r->increment_age();
12871289
}
12881290
}
12891291
}
12901292
}
1291-
1292-
ShenandoahHeap::heap()->set_concurrent_weak_root_in_progress(false);
12931293
}
12941294

12951295
void ShenandoahConcurrentGC::op_cleanup_complete() {

‎src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -1718,7 +1718,11 @@ class ShenandoahGenerationalEvacuationTask : public WorkerTask {
17181718
// doing this work during a safepoint. We cannot put humongous regions into the collection set because that
17191719
// triggers the load-reference barrier (LRB) to copy on reference fetch.
17201720
r->promote_humongous();
1721-
} else if (r->is_regular() && (r->garbage_before_padded_for_promote() < old_garbage_threshold) && (r->get_top_before_promote() == tams)) {
1721+
} else if (r->is_regular() && (r->get_top_before_promote() != nullptr)) {
1722+
assert(r->garbage_before_padded_for_promote() < old_garbage_threshold,
1723+
"Region " SIZE_FORMAT " has too much garbage for promotion", r->index());
1724+
assert(r->get_top_before_promote() == tams,
1725+
"Region " SIZE_FORMAT " has been used for allocations before promotion", r->index());
17221726
// Likewise, we cannot put promote-in-place regions into the collection set because that would also trigger
17231727
// the LRB to copy on reference fetch.
17241728
r->promote_in_place();
@@ -2996,7 +3000,7 @@ class ShenandoahFinalUpdateRefsUpdateRegionStateClosure : public ShenandoahHeapR
29963000
// Maintenance of region age must follow evacuation in order to account for evacuation allocations within survivor
29973001
// regions. We consult region age during the subsequent evacuation to determine whether certain objects need to
29983002
// be promoted.
2999-
if (_is_generational && r->is_young()) {
3003+
if (_is_generational && r->is_young() && r->is_active()) {
30003004
HeapWord *tams = _ctx->top_at_mark_start(r);
30013005
HeapWord *top = r->top();
30023006

‎src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ ShenandoahHeapRegion::ShenandoahHeapRegion(HeapWord* start, size_t index, bool c
7171
_end(start + RegionSizeWords),
7272
_new_top(nullptr),
7373
_empty_time(os::elapsedTime()),
74+
_top_before_promoted(nullptr),
7475
_state(committed ? _empty_committed : _empty_uncommitted),
7576
_top(start),
7677
_tlab_allocs(0),

‎src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ inline size_t ShenandoahHeapRegion::garbage() const {
185185
}
186186

187187
inline size_t ShenandoahHeapRegion::garbage_before_padded_for_promote() const {
188-
size_t used_before_promote = byte_size(bottom(), get_top_before_promote());
189188
assert(get_top_before_promote() != nullptr, "top before promote should not equal null");
189+
size_t used_before_promote = byte_size(bottom(), get_top_before_promote());
190190
assert(used_before_promote >= get_live_data_bytes(),
191191
"Live Data must be a subset of used before promotion live: " SIZE_FORMAT " used: " SIZE_FORMAT,
192192
get_live_data_bytes(), used_before_promote);
@@ -251,11 +251,8 @@ inline void ShenandoahHeapRegion::save_top_before_promote() {
251251

252252
inline void ShenandoahHeapRegion::restore_top_before_promote() {
253253
_top = _top_before_promoted;
254-
#ifdef ASSERT
255254
_top_before_promoted = nullptr;
256-
#endif
257255
}
258256

259257

260-
261258
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGION_INLINE_HPP

0 commit comments

Comments
 (0)
Please sign in to comment.