Skip to content

Commit b9ee954

Browse files
committed
8371200: ZGC: C2 allocation deopt race
Reviewed-by: aboldtch, stefank
1 parent f125c76 commit b9ee954

File tree

5 files changed

+60
-52
lines changed

5 files changed

+60
-52
lines changed

src/hotspot/share/gc/z/zBarrier.inline.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,6 @@ inline void ZBarrier::self_heal(ZBarrierFastPath fast_path, volatile zpointer* p
8686
assert(ZPointer::is_remapped(heal_ptr), "invariant");
8787

8888
for (;;) {
89-
if (ptr == zpointer::null) {
90-
assert(!ZVerifyOops || !ZHeap::heap()->is_in(uintptr_t(p)) || !ZHeap::heap()->is_old(p), "No raw null in old");
91-
}
92-
9389
assert_transition_monotonicity(ptr, heal_ptr);
9490

9591
// Heal

src/hotspot/share/gc/z/zBarrierSet.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -223,27 +223,7 @@ void ZBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) {
223223
// breaks that promise. Take a few steps in the interpreter instead, which has
224224
// no such assumptions about where an object resides.
225225
deoptimize_allocation(thread);
226-
return;
227226
}
228-
229-
if (!ZGeneration::young()->is_phase_mark_complete()) {
230-
return;
231-
}
232-
233-
if (!page->is_relocatable()) {
234-
return;
235-
}
236-
237-
if (ZRelocate::compute_to_age(age) != ZPageAge::old) {
238-
return;
239-
}
240-
241-
// If the object is young, we have to still be careful that it isn't racingly
242-
// about to get promoted to the old generation. That causes issues when null
243-
// pointers are supposed to be coloured, but the JIT is a bit sloppy and
244-
// reinitializes memory with raw nulls. We detect this situation and detune
245-
// rather than relying on the JIT to never be sloppy with redundant initialization.
246-
deoptimize_allocation(thread);
247227
}
248228

249229
void ZBarrierSet::print_on(outputStream* st) const {

src/hotspot/share/gc/z/zGeneration.cpp

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ static const ZStatSampler ZSamplerJavaThreads("System", "Java Threads", ZStatUni
111111
ZGenerationYoung* ZGeneration::_young;
112112
ZGenerationOld* ZGeneration::_old;
113113

114+
class ZRendezvousHandshakeClosure : public HandshakeClosure {
115+
public:
116+
ZRendezvousHandshakeClosure()
117+
: HandshakeClosure("ZRendezvous") {}
118+
119+
void do_thread(Thread* thread) {
120+
// Does nothing
121+
}
122+
};
123+
114124
ZGeneration::ZGeneration(ZGenerationId id, ZPageTable* page_table, ZPageAllocator* page_allocator)
115125
: _id(id),
116126
_page_allocator(page_allocator),
@@ -168,11 +178,19 @@ void ZGeneration::free_empty_pages(ZRelocationSetSelector* selector, int bulk) {
168178
}
169179

170180
void ZGeneration::flip_age_pages(const ZRelocationSetSelector* selector) {
171-
if (is_young()) {
172-
_relocate.flip_age_pages(selector->not_selected_small());
173-
_relocate.flip_age_pages(selector->not_selected_medium());
174-
_relocate.flip_age_pages(selector->not_selected_large());
175-
}
181+
_relocate.flip_age_pages(selector->not_selected_small());
182+
_relocate.flip_age_pages(selector->not_selected_medium());
183+
_relocate.flip_age_pages(selector->not_selected_large());
184+
185+
// Perform a handshake between flip promotion and running the promotion barrier. This ensures
186+
// that ZBarrierSet::on_slowpath_allocation_exit() observing a young page that was then racingly
187+
// flip promoted, will run any stores without barriers to completion before responding to the
188+
// handshake at the subsequent safepoint poll. This ensures that the flip promotion barriers always
189+
// run after compiled code missing barriers, but before relocate start.
190+
ZRendezvousHandshakeClosure cl;
191+
Handshake::execute(&cl);
192+
193+
_relocate.barrier_flip_promoted_pages(_relocation_set.flip_promoted_pages());
176194
}
177195

178196
static double fragmentation_limit(ZGenerationId generation) {
@@ -235,7 +253,9 @@ void ZGeneration::select_relocation_set(bool promote_all) {
235253
_relocation_set.install(&selector);
236254

237255
// Flip age young pages that were not selected
238-
flip_age_pages(&selector);
256+
if (is_young()) {
257+
flip_age_pages(&selector);
258+
}
239259

240260
// Setup forwarding table
241261
ZRelocationSetIterator rs_iter(&_relocation_set);
@@ -1280,16 +1300,6 @@ bool ZGenerationOld::uses_clear_all_soft_reference_policy() const {
12801300
return _reference_processor.uses_clear_all_soft_reference_policy();
12811301
}
12821302

1283-
class ZRendezvousHandshakeClosure : public HandshakeClosure {
1284-
public:
1285-
ZRendezvousHandshakeClosure()
1286-
: HandshakeClosure("ZRendezvous") {}
1287-
1288-
void do_thread(Thread* thread) {
1289-
// Does nothing
1290-
}
1291-
};
1292-
12931303
class ZRendezvousGCThreads: public VM_Operation {
12941304
public:
12951305
VMOp_Type type() const { return VMOp_ZRendezvousGCThreads; }

src/hotspot/share/gc/z/zRelocate.cpp

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,7 +1322,7 @@ class ZFlipAgePagesTask : public ZTask {
13221322

13231323
public:
13241324
ZFlipAgePagesTask(const ZArray<ZPage*>* pages)
1325-
: ZTask("ZPromotePagesTask"),
1325+
: ZTask("ZFlipAgePagesTask"),
13261326
_iter(pages) {}
13271327

13281328
virtual void work() {
@@ -1337,16 +1337,6 @@ class ZFlipAgePagesTask : public ZTask {
13371337
// Figure out if this is proper promotion
13381338
const bool promotion = to_age == ZPageAge::old;
13391339

1340-
if (promotion) {
1341-
// Before promoting an object (and before relocate start), we must ensure that all
1342-
// contained zpointers are store good. The marking code ensures that for non-null
1343-
// pointers, but null pointers are ignored. This code ensures that even null pointers
1344-
// are made store good, for the promoted objects.
1345-
prev_page->object_iterate([&](oop obj) {
1346-
ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field);
1347-
});
1348-
}
1349-
13501340
// Logging
13511341
prev_page->log_msg(promotion ? " (flip promoted)" : " (flip survived)");
13521342

@@ -1360,7 +1350,7 @@ class ZFlipAgePagesTask : public ZTask {
13601350

13611351
if (promotion) {
13621352
ZGeneration::young()->flip_promote(prev_page, new_page);
1363-
// Defer promoted page registration times the lock is taken
1353+
// Defer promoted page registration
13641354
promoted_pages.push(prev_page);
13651355
}
13661356

@@ -1371,11 +1361,42 @@ class ZFlipAgePagesTask : public ZTask {
13711361
}
13721362
};
13731363

1364+
class ZPromoteBarrierTask : public ZTask {
1365+
private:
1366+
ZArrayParallelIterator<ZPage*> _iter;
1367+
1368+
public:
1369+
ZPromoteBarrierTask(const ZArray<ZPage*>* pages)
1370+
: ZTask("ZPromoteBarrierTask"),
1371+
_iter(pages) {}
1372+
1373+
virtual void work() {
1374+
SuspendibleThreadSetJoiner sts_joiner;
1375+
1376+
for (ZPage* page; _iter.next(&page);) {
1377+
// When promoting an object (and before relocate start), we must ensure that all
1378+
// contained zpointers are store good. The marking code ensures that for non-null
1379+
// pointers, but null pointers are ignored. This code ensures that even null pointers
1380+
// are made store good, for the promoted objects.
1381+
page->object_iterate([&](oop obj) {
1382+
ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field);
1383+
});
1384+
1385+
SuspendibleThreadSet::yield();
1386+
}
1387+
}
1388+
};
1389+
13741390
void ZRelocate::flip_age_pages(const ZArray<ZPage*>* pages) {
13751391
ZFlipAgePagesTask flip_age_task(pages);
13761392
workers()->run(&flip_age_task);
13771393
}
13781394

1395+
void ZRelocate::barrier_flip_promoted_pages(const ZArray<ZPage*>* pages) {
1396+
ZPromoteBarrierTask promote_barrier_task(pages);
1397+
workers()->run(&promote_barrier_task);
1398+
}
1399+
13791400
void ZRelocate::synchronize() {
13801401
_queue.synchronize();
13811402
}

src/hotspot/share/gc/z/zRelocate.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class ZRelocate {
119119
void relocate(ZRelocationSet* relocation_set);
120120

121121
void flip_age_pages(const ZArray<ZPage*>* pages);
122+
void barrier_flip_promoted_pages(const ZArray<ZPage*>* pages);
122123

123124
void synchronize();
124125
void desynchronize();

0 commit comments

Comments
 (0)