Skip to content

Commit ef5e744

Browse files
author
Thomas Schatzl
committed
8372684: G1: Missing load_acquire() in G1 allocation path
Reviewed-by: kbarrett, sjohanss
1 parent 969eb1c commit ef5e744

File tree

3 files changed

+47
-44
lines changed

3 files changed

+47
-44
lines changed

src/hotspot/share/gc/g1/g1AllocRegion.cpp

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@
3333
#include "utilities/align.hpp"
3434

3535
G1CollectedHeap* G1AllocRegion::_g1h = nullptr;
36-
G1HeapRegion* G1AllocRegion::_dummy_region = nullptr;
36+
Atomic<G1HeapRegion*> G1AllocRegion::_dummy_region;
3737

3838
void G1AllocRegion::setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region) {
39-
assert(_dummy_region == nullptr, "should be set once");
39+
assert(_dummy_region.load_relaxed() == nullptr, "should be set once");
4040
assert(dummy_region != nullptr, "pre-condition");
4141
assert(dummy_region->free() == 0, "pre-condition");
4242

@@ -46,11 +46,11 @@ void G1AllocRegion::setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region) {
4646
assert(dummy_region->par_allocate(1, 1, &assert_tmp) == nullptr, "should fail");
4747

4848
_g1h = g1h;
49-
_dummy_region = dummy_region;
49+
_dummy_region.release_store(dummy_region);
5050
}
5151

5252
size_t G1AllocRegion::fill_up_remaining_space(G1HeapRegion* alloc_region) {
53-
assert(alloc_region != nullptr && alloc_region != _dummy_region,
53+
assert(alloc_region != nullptr && alloc_region != _dummy_region.load_relaxed(),
5454
"pre-condition");
5555
size_t result = 0;
5656

@@ -111,13 +111,13 @@ size_t G1AllocRegion::retire_internal(G1HeapRegion* alloc_region, bool fill_up)
111111
}
112112

113113
size_t G1AllocRegion::retire(bool fill_up) {
114-
assert_alloc_region(_alloc_region != nullptr, "not initialized properly");
114+
assert_alloc_region(_alloc_region.load_relaxed() != nullptr, "not initialized properly");
115115

116116
size_t waste = 0;
117117

118118
trace("retiring");
119-
G1HeapRegion* alloc_region = _alloc_region;
120-
if (alloc_region != _dummy_region) {
119+
G1HeapRegion* alloc_region = _alloc_region.load_acquire();
120+
if (alloc_region != _dummy_region.load_relaxed()) {
121121
waste = retire_internal(alloc_region, fill_up);
122122
reset_alloc_region();
123123
}
@@ -127,7 +127,7 @@ size_t G1AllocRegion::retire(bool fill_up) {
127127
}
128128

129129
HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) {
130-
assert_alloc_region(_alloc_region == _dummy_region, "pre-condition");
130+
assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed(), "pre-condition");
131131

132132
trace("attempting region allocation");
133133
G1HeapRegion* new_alloc_region = allocate_new_region(word_size);
@@ -138,7 +138,6 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) {
138138
HeapWord* result = new_alloc_region->allocate(word_size);
139139
assert_alloc_region(result != nullptr, "the allocation should succeeded");
140140

141-
OrderAccess::storestore();
142141
// Note that we first perform the allocation and then we store the
143142
// region in _alloc_region. This is the reason why an active region
144143
// can never be empty.
@@ -154,16 +153,16 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) {
154153

155154
void G1AllocRegion::init() {
156155
trace("initializing");
157-
assert_alloc_region(_alloc_region == nullptr, "pre-condition");
158-
assert_alloc_region(_dummy_region != nullptr, "should have been set");
159-
_alloc_region = _dummy_region;
156+
assert_alloc_region(_alloc_region.load_relaxed() == nullptr, "pre-condition");
157+
assert_alloc_region(_dummy_region.load_relaxed() != nullptr, "should have been set");
158+
_alloc_region.release_store(_dummy_region.load_relaxed());
160159
_count = 0;
161160
trace("initialized");
162161
}
163162

164163
void G1AllocRegion::set(G1HeapRegion* alloc_region) {
165164
trace("setting");
166-
assert_alloc_region(_alloc_region == _dummy_region && _count == 0, "pre-condition");
165+
assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed() && _count == 0, "pre-condition");
167166

168167
update_alloc_region(alloc_region);
169168
trace("set");
@@ -175,19 +174,19 @@ void G1AllocRegion::update_alloc_region(G1HeapRegion* alloc_region) {
175174
// maintain the "the alloc region cannot be empty" invariant.
176175
assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "pre-condition");
177176

178-
_alloc_region = alloc_region;
177+
_alloc_region.release_store(alloc_region);
179178
_count += 1;
180179
trace("updated");
181180
}
182181

183182
G1HeapRegion* G1AllocRegion::release() {
184183
trace("releasing");
185-
G1HeapRegion* alloc_region = _alloc_region;
184+
G1HeapRegion* alloc_region = _alloc_region.load_acquire();
186185
retire(false /* fill_up */);
187-
assert_alloc_region(_alloc_region == _dummy_region, "post-condition of retire()");
188-
_alloc_region = nullptr;
186+
assert_alloc_region(_alloc_region.load_relaxed() == _dummy_region.load_relaxed(), "post-condition of retire()");
187+
_alloc_region.store_relaxed(nullptr);
189188
trace("released");
190-
return (alloc_region == _dummy_region) ? nullptr : alloc_region;
189+
return (alloc_region == _dummy_region.load_relaxed()) ? nullptr : alloc_region;
191190
}
192191

193192
#ifndef PRODUCT
@@ -211,12 +210,13 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_
211210

212211
out->print("%s: %u ", _name, _count);
213212

214-
if (_alloc_region == nullptr) {
213+
G1HeapRegion* alloc_region = _alloc_region.load_acquire();
214+
if (alloc_region == nullptr) {
215215
out->print("null");
216-
} else if (_alloc_region == _dummy_region) {
216+
} else if (alloc_region == _dummy_region.load_relaxed()) {
217217
out->print("DUMMY");
218218
} else {
219-
out->print(HR_FORMAT, HR_FORMAT_PARAMS(_alloc_region));
219+
out->print(HR_FORMAT, HR_FORMAT_PARAMS(alloc_region));
220220
}
221221

222222
out->print(" : %s", str);
@@ -235,7 +235,7 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_
235235
#endif // PRODUCT
236236

237237
G1AllocRegion::G1AllocRegion(const char* name, uint node_index)
238-
: _alloc_region(nullptr),
238+
: _alloc_region(),
239239
_count(0),
240240
_name(name),
241241
_node_index(node_index)
@@ -250,7 +250,7 @@ void MutatorAllocRegion::retire_region(G1HeapRegion* alloc_region) {
250250
}
251251

252252
void MutatorAllocRegion::init() {
253-
assert(_retained_alloc_region == nullptr, "Pre-condition");
253+
assert(_retained_alloc_region.load_relaxed() == nullptr, "Pre-condition");
254254
G1AllocRegion::init();
255255
_wasted_bytes = 0;
256256
}
@@ -261,8 +261,9 @@ bool MutatorAllocRegion::should_retain(G1HeapRegion* region) {
261261
return false;
262262
}
263263

264-
if (_retained_alloc_region != nullptr &&
265-
free_bytes < _retained_alloc_region->free()) {
264+
G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
265+
if (retained_alloc_region != nullptr &&
266+
free_bytes < retained_alloc_region->free()) {
266267
return false;
267268
}
268269

@@ -278,10 +279,11 @@ size_t MutatorAllocRegion::retire(bool fill_up) {
278279
// free than the currently retained region.
279280
if (should_retain(current_region)) {
280281
trace("mutator retained");
281-
if (_retained_alloc_region != nullptr) {
282-
waste = retire_internal(_retained_alloc_region, true);
282+
G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
283+
if (retained_alloc_region != nullptr) {
284+
waste = retire_internal(retained_alloc_region, true);
283285
}
284-
_retained_alloc_region = current_region;
286+
_retained_alloc_region.release_store(current_region);
285287
} else {
286288
waste = retire_internal(current_region, fill_up);
287289
}
@@ -300,7 +302,7 @@ size_t MutatorAllocRegion::used_in_alloc_regions() {
300302
used += hr->used();
301303
}
302304

303-
hr = _retained_alloc_region;
305+
hr = _retained_alloc_region.load_acquire();
304306
if (hr != nullptr) {
305307
used += hr->used();
306308
}
@@ -313,9 +315,10 @@ G1HeapRegion* MutatorAllocRegion::release() {
313315
// The retained alloc region must be retired and this must be
314316
// done after the above call to release the mutator alloc region,
315317
// since it might update the _retained_alloc_region member.
316-
if (_retained_alloc_region != nullptr) {
317-
_wasted_bytes += retire_internal(_retained_alloc_region, false);
318-
_retained_alloc_region = nullptr;
318+
G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
319+
if (retained_alloc_region != nullptr) {
320+
_wasted_bytes += retire_internal(retained_alloc_region, false);
321+
_retained_alloc_region.store_relaxed(nullptr);
319322
}
320323
log_debug(gc, alloc, region)("Mutator Allocation stats, regions: %u, wasted size: %zu%s (%4.1f%%)",
321324
count(),

src/hotspot/share/gc/g1/g1AllocRegion.hpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "gc/g1/g1HeapRegion.hpp"
3030
#include "gc/g1/g1HeapRegionAttr.hpp"
3131
#include "gc/g1/g1NUMA.hpp"
32+
#include "runtime/atomic.hpp"
3233

3334
class G1CollectedHeap;
3435

@@ -40,8 +41,6 @@ class G1CollectedHeap;
4041
// replaced.
4142

4243
class G1AllocRegion : public CHeapObj<mtGC> {
43-
44-
private:
4544
// The active allocating region we are currently allocating out
4645
// of. The invariant is that if this object is initialized (i.e.,
4746
// init() has been called and release() has not) then _alloc_region
@@ -52,7 +51,7 @@ class G1AllocRegion : public CHeapObj<mtGC> {
5251
// then _alloc_region is null and this object should not be used to
5352
// satisfy allocation requests (it was done this way to force the
5453
// correct use of init() and release()).
55-
G1HeapRegion* volatile _alloc_region;
54+
Atomic<G1HeapRegion*> _alloc_region;
5655

5756
// It keeps track of the distinct number of regions that are used
5857
// for allocation in the active interval of this object, i.e.,
@@ -71,7 +70,7 @@ class G1AllocRegion : public CHeapObj<mtGC> {
7170
// == end()). When we don't have a valid active region we make
7271
// _alloc_region point to this. This allows us to skip checking
7372
// whether the _alloc_region is null or not.
74-
static G1HeapRegion* _dummy_region;
73+
static Atomic<G1HeapRegion*> _dummy_region;
7574

7675
// After a region is allocated by alloc_new_region, this
7776
// method is used to set it as the active alloc_region
@@ -124,9 +123,9 @@ class G1AllocRegion : public CHeapObj<mtGC> {
124123
static void setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region);
125124

126125
G1HeapRegion* get() const {
127-
G1HeapRegion * hr = _alloc_region;
126+
G1HeapRegion * hr = _alloc_region.load_acquire();
128127
// Make sure that the dummy region does not escape this class.
129-
return (hr == _dummy_region) ? nullptr : hr;
128+
return (hr == _dummy_region.load_relaxed()) ? nullptr : hr;
130129
}
131130

132131
uint count() { return _count; }
@@ -177,7 +176,7 @@ class MutatorAllocRegion : public G1AllocRegion {
177176
// Retained allocation region. Used to lower the waste generated
178177
// during mutation by having two active regions if the free space
179178
// in a region about to be retired still could fit a TLAB.
180-
G1HeapRegion* volatile _retained_alloc_region;
179+
Atomic<G1HeapRegion*> _retained_alloc_region;
181180

182181
// Decide if the region should be retained, based on the free size
183182
// in it and the free size in the currently retained region, if any.

src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@
3232
#define assert_alloc_region(p, message) \
3333
do { \
3434
assert((p), "[%s] %s c: %u r: " PTR_FORMAT, \
35-
_name, (message), _count, p2i(_alloc_region) \
35+
_name, (message), _count, p2i(_alloc_region.load_relaxed()) \
3636
); \
3737
} while (0)
3838

3939

4040
inline void G1AllocRegion::reset_alloc_region() {
41-
_alloc_region = _dummy_region;
41+
_alloc_region.store_relaxed(_dummy_region.load_relaxed());
4242
}
4343

4444
inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t word_size) {
@@ -51,7 +51,7 @@ inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t
5151
inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size,
5252
size_t desired_word_size,
5353
size_t* actual_word_size) {
54-
G1HeapRegion* alloc_region = _alloc_region;
54+
G1HeapRegion* alloc_region = _alloc_region.load_acquire();
5555
assert_alloc_region(alloc_region != nullptr && !alloc_region->is_empty(), "not initialized properly");
5656

5757
HeapWord* result = alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
@@ -97,8 +97,9 @@ inline HeapWord* G1AllocRegion::attempt_allocation_using_new_region(size_t min_w
9797
inline HeapWord* MutatorAllocRegion::attempt_retained_allocation(size_t min_word_size,
9898
size_t desired_word_size,
9999
size_t* actual_word_size) {
100-
if (_retained_alloc_region != nullptr) {
101-
HeapWord* result = _retained_alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
100+
G1HeapRegion* retained_alloc_region = _retained_alloc_region.load_acquire();
101+
if (retained_alloc_region != nullptr) {
102+
HeapWord* result = retained_alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
102103
if (result != nullptr) {
103104
trace("alloc retained", min_word_size, desired_word_size, *actual_word_size, result);
104105
return result;

0 commit comments

Comments
 (0)