8263427: Shenandoah: Trigger weak-LRB even when heap is stable

Reviewed-by: shade, zgu
This commit is contained in:
Roman Kennke 2021-03-16 14:12:42 +00:00
parent 4517d72fc2
commit 75ef6f580e
23 changed files with 226 additions and 77 deletions

View File

@ -342,7 +342,11 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
#endif
Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
__ testb(gc_state, ShenandoahHeap::HAS_FORWARDED);
int flags = ShenandoahHeap::HAS_FORWARDED;
if (!is_strong) {
flags |= ShenandoahHeap::WEAK_ROOTS;
}
__ testb(gc_state, flags);
__ jcc(Assembler::zero, heap_stable);
Register tmp1 = noreg, tmp2 = noreg;

View File

@ -138,7 +138,11 @@ LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier_impl(LIRGenerator* gen, L
// Read and check the gc-state-flag.
LIR_Opr flag_val = gen->new_register(T_INT);
__ load(active_flag_addr, flag_val);
LIR_Opr mask = LIR_OprFact::intConst(ShenandoahHeap::HAS_FORWARDED);
int flags = ShenandoahHeap::HAS_FORWARDED;
if (!ShenandoahBarrierSet::is_strong_access(decorators)) {
flags |= ShenandoahHeap::WEAK_ROOTS;
}
LIR_Opr mask = LIR_OprFact::intConst(flags);
LIR_Opr mask_reg = gen->new_register(T_INT);
__ move(mask, mask_reg);

View File

@ -1362,7 +1362,11 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM);
// Stable path.
test_gc_state(ctrl, raw_mem, heap_stable_ctrl, phase, ShenandoahHeap::HAS_FORWARDED);
int flags = ShenandoahHeap::HAS_FORWARDED;
if (!ShenandoahBarrierSet::is_strong_access(lrb->decorators())) {
flags |= ShenandoahHeap::WEAK_ROOTS;
}
test_gc_state(ctrl, raw_mem, heap_stable_ctrl, phase, flags);
IfNode* heap_stable_iff = heap_stable_ctrl->in(0)->as_If();
// Heap stable case

View File

@ -140,12 +140,6 @@ public:
inline void do_code_blob(CodeBlob* cb);
};
class ShenandoahRendezvousClosure : public HandshakeClosure {
public:
inline ShenandoahRendezvousClosure();
inline void do_thread(Thread* thread);
};
#ifdef ASSERT
class ShenandoahAssertNotForwardedClosure : public OopClosure {
private:

View File

@ -233,13 +233,6 @@ void ShenandoahCodeBlobAndDisarmClosure::do_code_blob(CodeBlob* cb) {
}
}
ShenandoahRendezvousClosure::ShenandoahRendezvousClosure() :
HandshakeClosure("ShenandoahRendezvous") {
}
void ShenandoahRendezvousClosure::do_thread(Thread* thread) {
}
#ifdef ASSERT
template <class T>
void ShenandoahAssertNotForwardedClosure::do_oop_work(T* p) {

View File

@ -166,11 +166,7 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) {
// Update references freed up collection set, kick the cleanup to reclaim the space.
entry_cleanup_complete();
} else {
// Concurrent weak/strong root flags are unset concurrently. We depend on updateref GC safepoints
// to ensure the changes are visible to all mutators before gc cycle is completed.
// In case of no evacuation, updateref GC safepoints are skipped. Therefore, we will need
// to perform thread handshake to ensure their consistences.
entry_rendezvous_roots();
vmop_entry_final_roots();
}
return true;
@ -216,6 +212,17 @@ void ShenandoahConcurrentGC::vmop_entry_final_updaterefs() {
VMThread::execute(&op);
}
void ShenandoahConcurrentGC::vmop_entry_final_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters());
ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_roots_gross);
// This phase does not use workers, no need for setup
heap->try_inject_alloc_failure();
VM_ShenandoahFinalRoots op(this);
VMThread::execute(&op);
}
void ShenandoahConcurrentGC::entry_init_mark() {
const char* msg = init_mark_event_message();
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::init_mark);
@ -261,6 +268,14 @@ void ShenandoahConcurrentGC::entry_final_updaterefs() {
op_final_updaterefs();
}
void ShenandoahConcurrentGC::entry_final_roots() {
static const char* msg = "Pause Final Roots";
ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_roots);
EventMark em("%s", msg);
op_final_roots();
}
void ShenandoahConcurrentGC::entry_reset() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
@ -393,18 +408,6 @@ void ShenandoahConcurrentGC::entry_cleanup_early() {
op_cleanup_early();
}
void ShenandoahConcurrentGC::entry_rendezvous_roots() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
static const char* msg = "Rendezvous roots";
ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_rendezvous_roots);
EventMark em("%s", msg);
// This phase does not use workers, no need for setup
heap->try_inject_alloc_failure();
op_rendezvous_roots();
}
void ShenandoahConcurrentGC::entry_evacuate() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
@ -804,16 +807,6 @@ void ShenandoahConcurrentGC::op_weak_roots() {
ShenandoahConcurrentWeakRootsEvacUpdateTask task(ShenandoahPhaseTimings::conc_weak_roots_work);
heap->workers()->run_task(&task);
}
// Perform handshake to flush out dead oops
{
ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_weak_roots_rendezvous);
heap->rendezvous_threads();
}
if (!ShenandoahHeap::heap()->unload_classes()) {
heap->set_concurrent_weak_root_in_progress(false);
}
}
void ShenandoahConcurrentGC::op_class_unloading() {
@ -822,7 +815,6 @@ void ShenandoahConcurrentGC::op_class_unloading() {
heap->unload_classes(),
"Checked by caller");
heap->do_class_unloading();
heap->set_concurrent_weak_root_in_progress(false);
}
class ShenandoahEvacUpdateCodeCacheClosure : public NMethodClosure {
@ -913,10 +905,6 @@ void ShenandoahConcurrentGC::op_cleanup_early() {
ShenandoahHeap::heap()->free_set()->recycle_trash();
}
void ShenandoahConcurrentGC::op_rendezvous_roots() {
ShenandoahHeap::heap()->rendezvous_threads();
}
void ShenandoahConcurrentGC::op_evacuate() {
ShenandoahHeap::heap()->evacuate_collection_set(true /*concurrent*/);
}
@ -924,6 +912,7 @@ void ShenandoahConcurrentGC::op_evacuate() {
void ShenandoahConcurrentGC::op_init_updaterefs() {
ShenandoahHeap* const heap = ShenandoahHeap::heap();
heap->set_evacuation_in_progress(false);
heap->set_concurrent_weak_root_in_progress(false);
heap->prepare_update_heap_references(true /*concurrent*/);
heap->set_update_refs_in_progress(true);
@ -995,6 +984,10 @@ void ShenandoahConcurrentGC::op_final_updaterefs() {
heap->rebuild_free_set(true /*concurrent*/);
}
void ShenandoahConcurrentGC::op_final_roots() {
ShenandoahHeap::heap()->set_concurrent_weak_root_in_progress(false);
}
void ShenandoahConcurrentGC::op_cleanup_complete() {
ShenandoahHeap::heap()->free_set()->recycle_trash();
}

View File

@ -40,6 +40,7 @@ class ShenandoahConcurrentGC : public ShenandoahGC {
friend class VM_ShenandoahFinalMarkStartEvac;
friend class VM_ShenandoahInitUpdateRefs;
friend class VM_ShenandoahFinalUpdateRefs;
friend class VM_ShenandoahFinalRoots;
private:
ShenandoahConcurrentMark _mark;
@ -59,6 +60,7 @@ private:
void vmop_entry_final_mark();
void vmop_entry_init_updaterefs();
void vmop_entry_final_updaterefs();
void vmop_entry_final_roots();
// Entry methods to normally STW GC operations. These set up logging, monitoring
// and workers for net VM operation
@ -66,6 +68,7 @@ private:
void entry_final_mark();
void entry_init_updaterefs();
void entry_final_updaterefs();
void entry_final_roots();
// Entry methods to normally concurrent GC operations. These set up logging, monitoring
// for concurrent operation.
@ -78,7 +81,6 @@ private:
void entry_class_unloading();
void entry_strong_roots();
void entry_cleanup_early();
void entry_rendezvous_roots();
void entry_evacuate();
void entry_update_thread_roots();
void entry_updaterefs();
@ -96,12 +98,12 @@ private:
void op_class_unloading();
void op_strong_roots();
void op_cleanup_early();
void op_rendezvous_roots();
void op_evacuate();
void op_init_updaterefs();
void op_updaterefs();
void op_update_thread_roots();
void op_final_updaterefs();
void op_final_roots();
void op_cleanup_complete();
// Messages for GC trace events, they have to be immortal for

View File

@ -124,10 +124,8 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) {
// Degenerated GC may carry concurrent root flags when upgrading to
// full GC. We need to reset it before mutators resume.
if (ClassUnloading) {
heap->set_concurrent_strong_root_in_progress(false);
heap->set_concurrent_weak_root_in_progress(false);
}
heap->set_concurrent_strong_root_in_progress(false);
heap->set_concurrent_weak_root_in_progress(false);
heap->set_full_gc_in_progress(true);

View File

@ -1545,11 +1545,6 @@ public:
bool is_thread_safe() { return true; }
};
void ShenandoahHeap::rendezvous_threads() {
ShenandoahRendezvousClosure cl;
Handshake::execute(&cl);
}
void ShenandoahHeap::recycle_trash() {
free_set()->recycle_trash();
}
@ -1655,7 +1650,6 @@ void ShenandoahHeap::prepare_regions_and_collection_set(bool concurrent) {
void ShenandoahHeap::do_class_unloading() {
_unloader.unload();
set_concurrent_weak_root_in_progress(false);
}
void ShenandoahHeap::stw_weak_refs(bool full_gc) {
@ -1714,12 +1708,8 @@ void ShenandoahHeap::set_concurrent_strong_root_in_progress(bool in_progress) {
}
}
void ShenandoahHeap::set_concurrent_weak_root_in_progress(bool in_progress) {
if (in_progress) {
_concurrent_weak_root_in_progress.set();
} else {
_concurrent_weak_root_in_progress.unset();
}
void ShenandoahHeap::set_concurrent_weak_root_in_progress(bool cond) {
set_gc_state_mask(WEAK_ROOTS, cond);
}
GCTracer* ShenandoahHeap::tracer() {

View File

@ -263,6 +263,9 @@ public:
// Heap is under updating: needs no additional barriers.
UPDATEREFS_BITPOS = 3,
// Heap is under weak-reference/roots processing: needs weak-LRB barriers.
WEAK_ROOTS_BITPOS = 4,
};
enum GCState {
@ -271,6 +274,7 @@ public:
MARKING = 1 << MARKING_BITPOS,
EVACUATION = 1 << EVACUATION_BITPOS,
UPDATEREFS = 1 << UPDATEREFS_BITPOS,
WEAK_ROOTS = 1 << WEAK_ROOTS_BITPOS,
};
private:
@ -280,7 +284,6 @@ private:
ShenandoahSharedFlag _full_gc_move_in_progress;
ShenandoahSharedFlag _progress_last_gc;
ShenandoahSharedFlag _concurrent_strong_root_in_progress;
ShenandoahSharedFlag _concurrent_weak_root_in_progress;
void set_gc_state_all_threads(char state);
void set_gc_state_mask(uint mask, bool value);
@ -367,7 +370,6 @@ private:
void update_heap_region_states(bool concurrent);
void rebuild_free_set(bool concurrent);
void rendezvous_threads();
void recycle_trash();
public:

View File

@ -340,7 +340,7 @@ inline bool ShenandoahHeap::is_concurrent_strong_root_in_progress() const {
}
inline bool ShenandoahHeap::is_concurrent_weak_root_in_progress() const {
return _concurrent_weak_root_in_progress.is_set();
return _gc_state.is_set(WEAK_ROOTS);
}
template<class T>

View File

@ -28,6 +28,7 @@
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/shenandoah/shenandoahNMethod.hpp"
#include "gc/shenandoah/shenandoahClosures.inline.hpp"
nmethod* ShenandoahNMethod::nm() const {
return _nm;

View File

@ -82,7 +82,6 @@ class outputStream;
f(conc_weak_roots, "Concurrent Weak Roots") \
f(conc_weak_roots_work, " Roots") \
SHENANDOAH_PAR_PHASE_DO(conc_weak_roots_work_, " CWR: ", f) \
f(conc_weak_roots_rendezvous, " Rendezvous") \
f(conc_cleanup_early, "Concurrent Cleanup") \
f(conc_class_unload, "Concurrent Class Unloading") \
f(conc_class_unload_unlink, " Unlink Stale") \
@ -96,9 +95,11 @@ class outputStream;
f(conc_class_unload_purge_ec, " Exception Caches") \
f(conc_strong_roots, "Concurrent Strong Roots") \
SHENANDOAH_PAR_PHASE_DO(conc_strong_roots_, " CSR: ", f) \
f(conc_rendezvous_roots, "Rendezvous") \
f(conc_evac, "Concurrent Evacuation") \
\
f(final_roots_gross, "Pause Final Roots (G)") \
f(final_roots, "Pause Final Roots (N)") \
\
f(init_update_refs_gross, "Pause Init Update Refs (G)") \
f(init_update_refs, "Pause Init Update Refs (N)") \
f(init_update_refs_manage_gclabs, " Manage GCLABs") \

View File

@ -46,13 +46,11 @@ ShenandoahGCStateResetter::ShenandoahGCStateResetter() :
_gc_state(_heap->gc_state()),
_concurrent_weak_root_in_progress(ShenandoahHeap::heap()->is_concurrent_weak_root_in_progress()) {
_heap->_gc_state.clear();
_heap->set_concurrent_weak_root_in_progress(false);
}
ShenandoahGCStateResetter::~ShenandoahGCStateResetter() {
_heap->_gc_state.set(_gc_state);
assert(_heap->gc_state() == _gc_state, "Should be restored");
_heap->set_concurrent_weak_root_in_progress(_concurrent_weak_root_in_progress);
}
void ShenandoahRootVerifier::roots_do(OopClosure* oops) {

View File

@ -31,8 +31,6 @@
#include "code/dependencyContext.hpp"
#include "gc/shared/gcBehaviours.hpp"
#include "gc/shared/suspendibleThreadSet.hpp"
#include "gc/shenandoah/shenandoahClosures.inline.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahNMethod.inline.hpp"
#include "gc/shenandoah/shenandoahLock.hpp"
#include "gc/shenandoah/shenandoahPhaseTimings.hpp"
@ -135,6 +133,12 @@ void ShenandoahUnload::prepare() {
DependencyContext::cleaning_start();
}
class ShenandoahRendezvousClosure : public HandshakeClosure {
public:
inline ShenandoahRendezvousClosure() : HandshakeClosure("ShenandoahRendezvous") {}
inline void do_thread(Thread* thread) {}
};
void ShenandoahUnload::unload() {
ShenandoahHeap* heap = ShenandoahHeap::heap();
assert(ClassUnloading, "Filtered by caller");

View File

@ -165,6 +165,7 @@ public:
type == VM_Operation::VMOp_ShenandoahFinalMarkStartEvac ||
type == VM_Operation::VMOp_ShenandoahInitUpdateRefs ||
type == VM_Operation::VMOp_ShenandoahFinalUpdateRefs ||
type == VM_Operation::VMOp_ShenandoahFinalRoots ||
type == VM_Operation::VMOp_ShenandoahFullGC ||
type == VM_Operation::VMOp_ShenandoahDegeneratedGC;
}

View File

@ -75,3 +75,8 @@ void VM_ShenandoahFinalUpdateRefs::doit() {
ShenandoahGCPauseMark mark(_gc_id, SvcGCMarker::CONCURRENT);
_gc->entry_final_updaterefs();
}
void VM_ShenandoahFinalRoots::doit() {
ShenandoahGCPauseMark mark(_gc_id, SvcGCMarker::CONCURRENT);
_gc->entry_final_roots();
}

View File

@ -130,4 +130,15 @@ public:
virtual void doit();
};
class VM_ShenandoahFinalRoots: public VM_ShenandoahOperation {
ShenandoahConcurrentGC* const _gc;
public:
VM_ShenandoahFinalRoots(ShenandoahConcurrentGC* gc) :
VM_ShenandoahOperation(),
_gc(gc) {};
VM_Operation::VMOp_Type type() const { return VMOp_ShenandoahFinalRoots; }
const char* name() const { return "Shenandoah Final Roots"; }
virtual void doit();
};
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHVMOPERATIONS_HPP

View File

@ -639,11 +639,23 @@ void ShenandoahVerifier::verify_at_safepoint(const char *label,
case _verify_gcstate_evacuation:
enabled = true;
expected = ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION;
if (!_heap->is_stw_gc_in_progress()) {
// Only concurrent GC sets this.
expected |= ShenandoahHeap::WEAK_ROOTS;
}
break;
case _verify_gcstate_stable:
enabled = true;
expected = ShenandoahHeap::STABLE;
break;
case _verify_gcstate_stable_weakroots:
enabled = true;
expected = ShenandoahHeap::STABLE;
if (!_heap->is_stw_gc_in_progress()) {
// Only concurrent GC sets this.
expected |= ShenandoahHeap::WEAK_ROOTS;
}
break;
default:
enabled = false;
assert(false, "Unhandled gc-state verification");
@ -799,7 +811,7 @@ void ShenandoahVerifier::verify_after_concmark() {
_verify_cset_none, // no references to cset anymore
_verify_liveness_complete, // liveness data must be complete here
_verify_regions_disable, // trash regions not yet recycled
_verify_gcstate_stable // mark should have stabilized the heap
_verify_gcstate_stable_weakroots // heap is still stable, weakroots are in progress
);
}
@ -811,7 +823,7 @@ void ShenandoahVerifier::verify_before_evacuation() {
_verify_cset_disable, // non-forwarded references to cset expected
_verify_liveness_complete, // liveness data must be complete here
_verify_regions_disable, // trash regions not yet recycled
_verify_gcstate_stable // mark should have stabilized the heap
_verify_gcstate_stable_weakroots // heap is still stable, weakroots are in progress
);
}

View File

@ -129,6 +129,9 @@ public:
// Nothing is in progress, no forwarded objects
_verify_gcstate_stable,
// Nothing is in progress, no forwarded objects, weak roots handling
_verify_gcstate_stable_weakroots,
// Nothing is in progress, some objects are forwarded
_verify_gcstate_forwarded,

View File

@ -88,6 +88,7 @@
template(ShenandoahFinalMarkStartEvac) \
template(ShenandoahInitUpdateRefs) \
template(ShenandoahFinalUpdateRefs) \
template(ShenandoahFinalRoots) \
template(ShenandoahDegeneratedGC) \
template(Exit) \
template(LinuxDllLoad) \

View File

@ -47,6 +47,32 @@ package gc.shenandoah;
* gc.shenandoah.TestReferenceRefersToShenandoah
*/
/* @test
* @requires vm.gc.Shenandoah
* @library /test/lib
* @build sun.hotspot.WhiteBox
* @modules java.base
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=satb -XX:ShenandoahGarbageThreshold=100 -Xmx100m
* gc.shenandoah.TestReferenceRefersToShenandoah
*/
/* @test
* @requires vm.gc.Shenandoah
* @library /test/lib
* @build sun.hotspot.WhiteBox
* @modules java.base
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGarbageThreshold=100 -Xmx100m
* gc.shenandoah.TestReferenceRefersToShenandoah
*/
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package gc.shenandoah;
/* @test
* @requires vm.gc.Shenandoah
* @library /test/lib
* @build sun.hotspot.WhiteBox
* @modules java.base
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=satb -XX:ShenandoahGarbageThreshold=100 -Xmx100m
* gc.shenandoah.TestReferenceShortcutCycle
*/
/* @test
* @requires vm.gc.Shenandoah
* @library /test/lib
* @build sun.hotspot.WhiteBox
* @modules java.base
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGarbageThreshold=100 -Xmx100m
* gc.shenandoah.TestReferenceShortcutCycle
*/
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import sun.hotspot.WhiteBox;
public class TestReferenceShortcutCycle {
private static final int NUM_ITEMS = 100000;
private static final WhiteBox WB = WhiteBox.getWhiteBox();
private static final class TestObject {
public final int value;
public TestObject(int value) {
this.value = value;
}
}
private static WeakReference[] refs;
private static void setup() {
refs = new WeakReference[NUM_ITEMS];
for (int i = 0; i < NUM_ITEMS; i++) {
refs[i] = new WeakReference<>(new TestObject(i));
}
}
private static void fail(String msg) throws Exception {
throw new RuntimeException(msg);
}
private static void testConcurrentCollection() throws Exception {
setup();
WB.concurrentGCAcquireControl();
try {
WB.concurrentGCRunToIdle();
WB.concurrentGCRunTo(WB.AFTER_CONCURRENT_REFERENCE_PROCESSING_STARTED);
for (int i = 0; i < NUM_ITEMS; i++) {
if (refs[i].get() != null) {
fail("resurrected referent");
}
}
} finally {
WB.concurrentGCReleaseControl();
}
}
public static void main(String[] args) throws Exception {
testConcurrentCollection();
}
}